From cdb205e696ea3fb717d06c986d29a328e1009128 Mon Sep 17 00:00:00 2001 From: upthorn Date: Fri, 31 Aug 2018 21:21:34 -0700 Subject: [PATCH 001/440] Initial API Work --- .../BizHawk.Client.Common.csproj | 11 + .../lua/EmuLuaLibrary.SQL.cs | 3 +- BizHawk.Client.Common/plugins/PluginBase.cs | 58 ++ .../plugins/PluginLibrary.Emu.cs | 353 +++++++++++++ .../plugins/PluginLibrary.GUIDraw.cs | 498 ++++++++++++++++++ .../plugins/PluginLibrary.Gameinfo.cs | 86 +++ .../plugins/PluginLibrary.Joypad.cs | 186 +++++++ .../plugins/PluginLibrary.Memory.cs | 284 ++++++++++ .../plugins/PluginLibrary.MemorySavestate.cs | 60 +++ .../plugins/PluginLibrary.Movie.cs | 263 +++++++++ .../plugins/PluginLibrary.UserData.cs | 52 ++ .../plugins/PluginMemoryBase.cs | 242 +++++++++ .../BizHawk.Client.EmuHawk.csproj | 2 + .../Plugins/Libraries/GUIDrawLibrary.cs | 167 ++++++ 14 files changed, 2263 insertions(+), 2 deletions(-) create mode 100644 BizHawk.Client.Common/plugins/PluginBase.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs create mode 100644 BizHawk.Client.Common/plugins/PluginMemoryBase.cs create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 9816bf2bfb..18110a72f2 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -64,6 +64,7 @@ + @@ -131,6 +132,16 @@ + + + + + + + + + + diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.SQL.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.SQL.cs index 5738e975db..5cbc8d2df2 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.SQL.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.SQL.cs @@ -1,9 +1,8 @@ using System; -using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Data.SQLite; using NLua; -using System.Collections.Generic; namespace BizHawk.Client.Common { diff --git a/BizHawk.Client.Common/plugins/PluginBase.cs b/BizHawk.Client.Common/plugins/PluginBase.cs new file mode 100644 index 0000000000..44f88da68c --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginBase.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Client.Common +{ + public abstract class PluginBase + { + [RequiredService] + private IEmulator Emulator { get; set; } + + [RequiredService] + private IMemoryDomains Domains { get; set; } + + [OptionalService] + private IInputPollable InputPollableCore { get; set; } + + [OptionalService] + private IDebuggable DebuggableCore { get; set; } + + public abstract void PreFrameCallback(); + public abstract void PostFrameCallback(); + public abstract void SaveStateCallback(string name); + public abstract void LoadStateCallback(string name); + public abstract void InputPollCallback(); + + protected virtual void AddReadCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Read, "Lua Hook", cb, address, null)); + } + } + protected virtual void AddWriteCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Write, "Lua Hook", cb, address, null)); + } + } + protected virtual void AddExecCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable() && DebuggableCore.MemoryCallbacks.ExecuteCallbacksAvailable) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Execute, "Lua Hook", cb, address, null)); + } + } + protected virtual void RemoveMemoryCallback(Action cb) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Remove(cb); + } + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs new file mode 100644 index 0000000000..eb3dd485b9 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs @@ -0,0 +1,353 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SNES; +using BizHawk.Emulation.Cores.PCEngine; +using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; +using BizHawk.Emulation.Cores.Sega.MasterSystem; +using BizHawk.Emulation.Cores.WonderSwan; +using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; + +namespace BizHawk.Client.Common +{ + [Description("A library for interacting with the currently loaded emulator core")] + public sealed class EmulatorPluginLibrary + { + [RequiredService] + private IEmulator Emulator { get; set; } + + [OptionalService] + private IDebuggable DebuggableCore { get; set; } + + [OptionalService] + private IDisassemblable DisassemblableCore { get; set; } + + [OptionalService] + private IMemoryDomains MemoryDomains { get; set; } + + [OptionalService] + private IInputPollable InputPollableCore { get; set; } + + [OptionalService] + private IRegionable RegionableCore { get; set; } + + [OptionalService] + private IBoardInfo BoardInfo { get; set; } + + public Action FrameAdvanceCallback { get; set; } + public Action YieldCallback { get; set; } + + public EmulatorPluginLibrary() + { } + + public static void DisplayVsync(bool enabled) + { + Global.Config.VSync = enabled; + } + + public void FrameAdvance() + { + FrameAdvanceCallback(); + } + + public int FrameCount() + { + return Emulator.Frame; + } + + public object Disassemble(uint pc, string name = "") + { + try + { + if (DisassemblableCore == null) + { + throw new NotImplementedException(); + } + + MemoryDomain domain = MemoryDomains.SystemBus; + + if (!string.IsNullOrEmpty(name)) + { + domain = MemoryDomains[name]; + } + + var d = DisassemblableCore.Disassemble(domain, pc, out int l); + return new { disasm = d, length = l }; + } + catch (NotImplementedException) + { + Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement disassemble()"); + return null; + } + } + + public ulong? GetRegister(string name) + { + try + { + if (DebuggableCore == null) + { + throw new NotImplementedException(); + } + + var registers = DebuggableCore.GetCpuFlagsAndRegisters(); + ulong? value = null; + if (registers.ContainsKey(name)) value = registers[name].Value; + return value; + } + catch (NotImplementedException) + { + Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement getregister()"); + return null; + } + } + + public Dictionary GetRegisters() + { + var table = new Dictionary(); + + try + { + if (DebuggableCore == null) + { + throw new NotImplementedException(); + } + + foreach (var kvp in DebuggableCore.GetCpuFlagsAndRegisters()) + { + table[kvp.Key] = kvp.Value.Value; + } + } + catch (NotImplementedException) + { + Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement getregisters()"); + } + + return table; + } + + public void SetRegister(string register, int value) + { + try + { + if (DebuggableCore == null) + { + throw new NotImplementedException(); + } + + DebuggableCore.SetCpuRegister(register, value); + } + catch (NotImplementedException) + { + Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement setregister()"); + } + } + + public long TotalExecutedycles() + { + try + { + if (DebuggableCore == null) + { + throw new NotImplementedException(); + } + + return DebuggableCore.TotalExecutedCycles; + } + catch (NotImplementedException) + { + Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement totalexecutedcycles()"); + + return 0; + } + } + + public static string GetSystemId() + { + return Global.Game.System; + } + + public bool IsLagged() + { + if (InputPollableCore != null) + { + return InputPollableCore.IsLagFrame; + } + + Console.WriteLine($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable"); + return false; + } + + public void SetIsLagged(bool value = true) + { + if (InputPollableCore != null) + { + InputPollableCore.IsLagFrame = value; + } + else + { + Console.WriteLine($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable"); + } + } + + public int LagCount() + { + if (InputPollableCore != null) + { + return InputPollableCore.LagCount; + } + + Console.WriteLine($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable"); + return 0; + } + + public void SetLagCount(int count) + { + if (InputPollableCore != null) + { + InputPollableCore.LagCount = count; + } + else + { + Console.WriteLine($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable"); + } + } + + public static void LimitFramerate(bool enabled) + { + Global.Config.ClockThrottle = enabled; + } + + public static void MinimizeFrameskip(bool enabled) + { + Global.Config.AutoMinimizeSkipping = enabled; + } + + public void SetRenderPlanes(params bool[] luaParam) + { + if (Emulator is GPGX) + { + var gpgx = Emulator as GPGX; + var s = gpgx.GetSettings(); + s.DrawBGA = luaParam[0]; + s.DrawBGB = luaParam[1]; + s.DrawBGW = luaParam[2]; + s.DrawObj = luaParam[3]; + gpgx.PutSettings(s); + + } + else if (Emulator is LibsnesCore) + { + var snes = Emulator as LibsnesCore; + var s = snes.GetSettings(); + s.ShowBG1_0 = s.ShowBG1_1 = luaParam[0]; + s.ShowBG2_0 = s.ShowBG2_1 = luaParam[1]; + s.ShowBG3_0 = s.ShowBG3_1 = luaParam[2]; + s.ShowBG4_0 = s.ShowBG4_1 = luaParam[3]; + s.ShowOBJ_0 = luaParam[4]; + s.ShowOBJ_1 = luaParam[5]; + s.ShowOBJ_2 = luaParam[6]; + s.ShowOBJ_3 = luaParam[7]; + snes.PutSettings(s); + } + else if (Emulator is NES) + { + // in the future, we could do something more arbitrary here. + // but this isn't any worse than the old system + var nes = Emulator as NES; + var s = nes.GetSettings(); + s.DispSprites = luaParam[0]; + s.DispBackground = luaParam[1]; + nes.PutSettings(s); + } + else if (Emulator is QuickNES) + { + var quicknes = Emulator as QuickNES; + var s = quicknes.GetSettings(); + + // this core doesn't support disabling BG + bool showsp = GetSetting(0, luaParam); + if (showsp && s.NumSprites == 0) + { + s.NumSprites = 8; + } + else if (!showsp && s.NumSprites > 0) + { + s.NumSprites = 0; + } + + quicknes.PutSettings(s); + } + else if (Emulator is PCEngine) + { + var pce = Emulator as PCEngine; + var s = pce.GetSettings(); + s.ShowOBJ1 = GetSetting(0, luaParam); + s.ShowBG1 = GetSetting(1, luaParam); + if (luaParam.Length > 2) + { + s.ShowOBJ2 = GetSetting(2, luaParam); + s.ShowBG2 = GetSetting(3, luaParam); + } + + pce.PutSettings(s); + } + else if (Emulator is SMS) + { + var sms = Emulator as SMS; + var s = sms.GetSettings(); + s.DispOBJ = GetSetting(0, luaParam); + s.DispBG = GetSetting(1, luaParam); + sms.PutSettings(s); + } + else if (Emulator is WonderSwan) + { + var ws = Emulator as WonderSwan; + var s = ws.GetSettings(); + s.EnableSprites = GetSetting(0, luaParam); + s.EnableFG = GetSetting(1, luaParam); + s.EnableBG = GetSetting(2, luaParam); + ws.PutSettings(s); + } + } + + private static bool GetSetting(int index, bool[] settings) + { + if (index < settings.Length) + { + return settings[index]; + } + + return true; + } + + public void Yield() + { + YieldCallback(); + } + + public string GetDisplayType() + { + if (RegionableCore != null) + { + return RegionableCore.Region.ToString(); + } + + return ""; + } + + public string GetBoardName() + { + if (BoardInfo != null) + { + return BoardInfo.BoardName; + } + + return ""; + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs new file mode 100644 index 0000000000..46081390d2 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs @@ -0,0 +1,498 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using System.IO; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public abstract class GUIDrawPluginLibrary + { + [RequiredService] + protected IEmulator Emulator { get; set; } + + public GUIDrawPluginLibrary() + { + + } + + public bool HasGUISurface = false; + + protected Color _defaultForeground = Color.White; + protected Color? _defaultBackground; + protected Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); + protected int _defaultPixelFont = 1; // gens + protected Padding _padding = new Padding(0); + + #region Gui API + public virtual void Dispose() + { + foreach (var brush in _solidBrushes.Values) + { + brush.Dispose(); + } + + foreach (var brush in _pens.Values) + { + brush.Dispose(); + } + } + + public abstract void DrawNew(string name, bool? clear = true); + public abstract void DrawFinish(); + #endregion + + #region Helpers + protected readonly Dictionary _imageCache = new Dictionary(); + + protected readonly Dictionary _solidBrushes = new Dictionary(); + protected readonly Dictionary _pens = new Dictionary(); + protected SolidBrush GetBrush(Color color) + { + SolidBrush b; + if (!_solidBrushes.TryGetValue(color, out b)) + { + b = new SolidBrush(color); + _solidBrushes[color] = b; + } + + return b; + } + + protected Pen GetPen(Color color) + { + Pen p; + if (!_pens.TryGetValue(color, out p)) + { + p = new Pen(color); + _pens[color] = p; + } + + return p; + } + + protected abstract Graphics GetGraphics(); + public void SetPadding(int all) + { + _padding = new Padding(all); + } + public void SetPadding(int x, int y) + { + _padding = new Padding(x / 2, y / 2, x / 2 + x & 1, y / 2 + y & 1); + } + public void SetPadding(int l,int t,int r, int b) + { + _padding = new Padding(l, t, r, b); + } + public Padding GetPadding() + { + return _padding; + } + #endregion + + public abstract void AddMessage(string message); + + public abstract void ClearGraphics(); + + public abstract void ClearText(); + + public void SetDefaultForegroundColor(Color color) + { + _defaultForeground = color; + } + + public void SetDefaultBackgroundColor(Color color) + { + _defaultBackground = color; + } + + public void SetDefaultTextBackground(Color color) + { + _defaultTextBackground = color; + } + + public void SetDefaultPixelFont(string fontfamily) + { + switch (fontfamily) + { + case "fceux": + case "0": + _defaultPixelFont = 0; + break; + case "gens": + case "1": + _defaultPixelFont = 1; + break; + default: + Console.WriteLine($"Unable to find font family: {fontfamily}"); + return; + } + } + + public void DrawBezier(Point p1, Point p2, Point p3, Point p4, Color? color = null) + { + using (var g = GetGraphics()) + { + try + { + g.DrawBezier(GetPen(color ?? _defaultForeground), p1, p2, p3, p4); + } + catch (Exception) + { + return; + } + } + } + + public void DrawBeziers(Point[] points, Color? color = null) + { + using (var g = GetGraphics()) + { + try + { + g.DrawBeziers(GetPen(color ?? _defaultForeground), points); + } + catch (Exception) + { + return; + } + } + } + public void DrawBox(int x, int y, int x2, int y2, Color? line = null, Color? background = null) + { + using (var g = GetGraphics()) + { + try + { + if (x < x2) + { + x2 = Math.Abs(x - x2); + } + else + { + x2 = x - x2; + x -= x2; + } + + if (y < y2) + { + y2 = Math.Abs(y - y2); + } + else + { + y2 = y - y2; + y -= y2; + } + + g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, x2, y2); + + var bg = background ?? _defaultBackground; + if (bg.HasValue) + { + g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, x2 - 1, y2 - 1); + } + } + catch (Exception) + { + // need to stop the script from here + return; + } + } + } + + public void DrawEllipse(int x, int y, int width, int height, Color? line = null, Color? background = null) + { + using (var g = GetGraphics()) + { + try + { + var bg = background ?? _defaultBackground; + if (bg.HasValue) + { + var brush = GetBrush(bg.Value); + g.FillEllipse(brush, x, y, width, height); + } + + g.DrawEllipse(GetPen(line ?? _defaultForeground), x, y, width, height); + } + catch (Exception) + { + // need to stop the script from here + return; + } + } + } + + public void DrawIcon(string path, int x, int y, int? width = null, int? height = null) + { + using (var g = GetGraphics()) + { + try + { + if (!File.Exists(path)) + { + AddMessage("File not found: " + path); + return; + } + + Icon icon; + if (width.HasValue && height.HasValue) + { + icon = new Icon(path, width.Value, height.Value); + } + else + { + icon = new Icon(path); + } + + g.DrawIcon(icon, x, y); + } + catch (Exception) + { + return; + } + } + } + + public void DrawImage(string path, int x, int y, int? width = null, int? height = null, bool cache = true) + { + if (!File.Exists(path)) + { + Console.WriteLine("File not found: " + path); + return; + } + + using (var g = GetGraphics()) + { + Image img; + if (_imageCache.ContainsKey(path)) + { + img = _imageCache[path]; + } + else + { + img = Image.FromFile(path); + if (cache) + { + _imageCache.Add(path, img); + } + } + + g.DrawImage(img, x, y, width ?? img.Width, height ?? img.Height); + } + } + + public void ClearImageCache() + { + foreach (var image in _imageCache) + { + image.Value.Dispose(); + } + + _imageCache.Clear(); + } + + public void DrawImageRegion(string path, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int? dest_width = null, int? dest_height = null) + { + if (!File.Exists(path)) + { + Console.WriteLine("File not found: " + path); + return; + } + + using (var g = GetGraphics()) + { + Image img; + if (_imageCache.ContainsKey(path)) + { + img = _imageCache[path]; + } + else + { + img = Image.FromFile(path); + _imageCache.Add(path, img); + } + + var destRect = new Rectangle(dest_x, dest_y, dest_width ?? source_width, dest_height ?? source_height); + + g.DrawImage(img, destRect, source_x, source_y, source_width, source_height, GraphicsUnit.Pixel); + } + } + + public void DrawLine(int x1, int y1, int x2, int y2, Color? color = null) + { + using (var g = GetGraphics()) + { + g.DrawLine(GetPen(color ?? _defaultForeground), x1, y1, x2, y2); + } + } + + public void DrawAxis(int x, int y, int size, Color? color = null) + { + DrawLine(x + size, y, x - size, y, color ?? _defaultForeground); + DrawLine(x, y + size, x, y - size, color ?? _defaultForeground); + } + + public void DrawPie(int x, int y, int width, int height, int startangle, int sweepangle, Color? line = null, Color? background = null) + { + using (var g = GetGraphics()) + { + var bg = background ?? _defaultBackground; + if (bg.HasValue) + { + var brush = GetBrush(bg.Value); + g.FillPie(brush, x, y, width, height, startangle, sweepangle); + } + + g.DrawPie(GetPen(line ?? _defaultForeground), x + 1, y + 1, width - 1, height - 1, startangle, sweepangle); + } + } + + public void DrawPixel(int x, int y, Color? color = null) + { + using (var g = GetGraphics()) + { + try + { + g.DrawLine(GetPen(color ?? _defaultForeground), x, y, x + 0.1F, y); + } + catch (Exception) + { + return; + } + } + } + + public void DrawPolygon(Point[] points, Color? line = null, Color? background = null) + { + using (var g = GetGraphics()) + { + try + { + g.DrawPolygon(GetPen(line ?? _defaultForeground), points); + var bg = background ?? _defaultBackground; + if (bg.HasValue) + { + g.FillPolygon(GetBrush(bg.Value), points); + } + } + catch (Exception) + { + return; + } + } + } + + public void DrawRectangle(int x, int y, int width, int height, Color? line = null, Color? background = null) + { + using (var g = GetGraphics()) + { + g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, width, height); + var bg = background ?? _defaultBackground; + if (bg.HasValue) + { + g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, width - 1, height - 1); + } + } + } + + public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null, + string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null) + { + using (var g = GetGraphics()) + { + try + { + var family = FontFamily.GenericMonospace; + if (fontfamily != null) + { + family = new FontFamily(fontfamily); + } + + var fstyle = FontStyle.Regular; + if (fontstyle != null) + { + switch (fontstyle.ToLower()) + { + default: + case "regular": + break; + case "bold": + fstyle = FontStyle.Bold; + break; + case "italic": + fstyle = FontStyle.Italic; + break; + case "strikethrough": + fstyle = FontStyle.Strikeout; + break; + case "underline": + fstyle = FontStyle.Underline; + break; + } + } + + // The text isn't written out using GenericTypographic, so measuring it using GenericTypographic seemed to make it worse. + // And writing it out with GenericTypographic just made it uglier. :p + var f = new StringFormat(StringFormat.GenericDefault); + var font = new Font(family, fontsize ?? 12, fstyle, GraphicsUnit.Pixel); + Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize(); + if (horizalign != null) + { + switch (horizalign.ToLower()) + { + default: + case "left": + break; + case "center": + x -= sizeOfText.Width / 2; + break; + case "right": + x -= sizeOfText.Width; + break; + } + } + + if (vertalign != null) + { + switch (vertalign.ToLower()) + { + default: + case "bottom": + break; + case "middle": + y -= sizeOfText.Height / 2; + break; + case "top": + y -= sizeOfText.Height; + break; + } + } + + var bg = backcolor ?? _defaultBackground; + if (bg.HasValue) + { + for (var xd = -1; xd <= 1; xd++) + { + for (var yd = -1; yd <= 1; yd++) + { + g.DrawString(message, font, GetBrush(bg.Value), x+xd, y+yd); + } + } + } + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; + g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y); + } + catch (Exception) + { + return; + } + } + } + + public abstract void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null); + public abstract void Text(int x, int y, string message, Color? forecolor = null, string anchor = null); + } +} \ No newline at end of file diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs new file mode 100644 index 0000000000..6c9c21b070 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public sealed class GameInfoPluginLibrary + { + [OptionalService] + private IBoardInfo BoardInfo { get; set; } + + public GameInfoPluginLibrary() + { } + + public string GetRomName() + { + if (Global.Game != null) + { + return Global.Game.Name ?? ""; + } + + return ""; + } + + public string GetRomHash() + { + if (Global.Game != null) + { + return Global.Game.Hash ?? ""; + } + + return ""; + } + + public bool InDatabase() + { + if (Global.Game != null) + { + return !Global.Game.NotInDatabase; + } + + return false; + } + + public string GetStatus() + { + if (Global.Game != null) + { + return Global.Game.Status.ToString(); + } + + return ""; + } + + public bool IsStatusBad() + { + if (Global.Game != null) + { + return Global.Game.IsRomStatusBad(); + } + + return true; + } + + public string GetBoardType() + { + return BoardInfo?.BoardName ?? ""; + } + + public Dictionary GetOptions() + { + var options = new Dictionary(); + + if (Global.Game != null) + { + foreach (var option in Global.Game.GetOptionsDict()) + { + options[option.Key] = option.Value; + } + } + + return options; + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs new file mode 100644 index 0000000000..e981b0ef31 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; + +namespace BizHawk.Client.Common +{ + public sealed class JoypadPluginLibrary + { + public JoypadPluginLibrary() { } + + public Dictionary Get(int? controller = null) + { + var buttons = new Dictionary(); + var adaptor = Global.AutofireStickyXORAdapter; + foreach (var button in adaptor.Source.Definition.BoolButtons) + { + if (!controller.HasValue) + { + buttons[button] = adaptor.IsPressed(button); + } + else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller) + { + buttons[button.Substring(3)] = adaptor.IsPressed("P" + controller + " " + button.Substring(3)); + } + } + + foreach (var button in adaptor.Source.Definition.FloatControls) + { + if (controller == null) + { + buttons[button] = adaptor.GetFloat(button); + } + else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller) + { + buttons[button.Substring(3)] = adaptor.GetFloat("P" + controller + " " + button.Substring(3)); + } + } + + buttons["clear"] = null; + buttons["getluafunctionslist"] = null; + buttons["output"] = null; + + return buttons; + } + + // TODO: what about float controls? + public Dictionary GetImmediate() + { + var buttons = new Dictionary(); + var adaptor = Global.ActiveController; + foreach (var button in adaptor.Definition.BoolButtons) + { + buttons[button] = adaptor.IsPressed(button); + } + foreach (var button in adaptor.Definition.FloatControls) + { + buttons[button] = adaptor.GetFloat(button); + } + + return buttons; + } + + public void SetFromMnemonicStr(string inputLogEntry) + { + try + { + var lg = Global.MovieSession.MovieControllerInstance(); + lg.SetControllersAsMnemonic(inputLogEntry); + + foreach (var button in lg.Definition.BoolButtons) + { + Global.LuaAndAdaptor.SetButton(button, lg.IsPressed(button)); + } + + foreach (var floatButton in lg.Definition.FloatControls) + { + Global.LuaAndAdaptor.SetFloat(floatButton, lg.GetFloat(floatButton)); + } + } + catch (Exception) + { + Console.WriteLine("invalid mnemonic string: " + inputLogEntry); + } + } + + [LuaMethodExample("joypad.set( { [\"Left\"] = true, [ \"A\" ] = true, [ \"B\" ] = true } );")] + [LuaMethod("set", "sets the given buttons to their provided values for the current frame")] + public void Set(Dictionary buttons, int? controller = null) + { + try + { + foreach (var button in buttons.Keys) + { + var invert = false; + bool? theValue; + var theValueStr = buttons[button].ToString(); + + if (!string.IsNullOrWhiteSpace(theValueStr)) + { + if (theValueStr.ToLower() == "false") + { + theValue = false; + } + else if (theValueStr.ToLower() == "true") + { + theValue = true; + } + else + { + invert = true; + theValue = null; + } + } + else + { + theValue = null; + } + + var toPress = button.ToString(); + if (controller.HasValue) + { + toPress = "P" + controller + " " + button; + } + + if (!invert) + { + if (theValue.HasValue) // Force + { + Global.LuaAndAdaptor.SetButton(toPress, theValue.Value); + Global.ActiveController.Overrides(Global.LuaAndAdaptor); + } + else // Unset + { + Global.LuaAndAdaptor.UnSet(toPress); + Global.ActiveController.Overrides(Global.LuaAndAdaptor); + } + } + else // Inverse + { + Global.LuaAndAdaptor.SetInverse(toPress); + Global.ActiveController.Overrides(Global.LuaAndAdaptor); + } + } + } + catch + { + /*Eat it*/ + } + } + + [LuaMethodExample("joypad.setanalog( { [ \"Tilt X\" ] = true, [ \"Tilt Y\" ] = false } );")] + [LuaMethod("setanalog", "sets the given analog controls to their provided values for the current frame. Note that unlike set() there is only the logic of overriding with the given value.")] + public void SetAnalog(Dictionary controls, object controller = null) + { + try + { + foreach (var name in controls.Keys) + { + var theValueStr = controls[name].ToString(); + float? theValue = null; + + if (!string.IsNullOrWhiteSpace(theValueStr)) + { + float f; + if (float.TryParse(theValueStr, out f)) + { + theValue = f; + } + } + + if (controller == null) + { + Global.StickyXORAdapter.SetFloat(name.ToString(), theValue); + } + else + { + Global.StickyXORAdapter.SetFloat("P" + controller + " " + name, theValue); + } + } + } + catch + { + /*Eat it*/ + } + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs new file mode 100644 index 0000000000..aa9daf90d3 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Common.BufferExtensions; + +namespace BizHawk.Client.Common +{ + public sealed class MemoryPluginLibrary : PluginMemoryBase + { + private MemoryDomain _currentMemoryDomain; + private bool _isBigEndian; + public MemoryPluginLibrary(bool Big = false) + : base() + { + _isBigEndian = Big; + } + + protected override MemoryDomain Domain + { + get + { + if (MemoryDomainCore != null) + { + if (_currentMemoryDomain == null) + { + _currentMemoryDomain = MemoryDomainCore.HasSystemBus + ? MemoryDomainCore.SystemBus + : MemoryDomainCore.MainMemory; + } + + return _currentMemoryDomain; + } + + var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains"; + Console.WriteLine(error); + throw new NotImplementedException(error); + } + } + + #region Unique Library Methods + + public List GetMemoryDomainList() + { + var list = new List(); + + foreach (var domain in DomainList) + { + list.Add(domain.Name); + } + + return list; + } + + public uint GetMemoryDomainSize(string name = "") + { + if (string.IsNullOrEmpty(name)) + { + return (uint)Domain.Size; + } + + return (uint)DomainList[VerifyMemoryDomain(name)].Size; + } + + public string GetCurrentMemoryDomain() + { + return Domain.Name; + } + + public uint GetCurrentMemoryDomainSize() + { + return (uint)Domain.Size; + } + + public bool UseMemoryDomain(string domain) + { + try + { + if (DomainList[domain] != null) + { + _currentMemoryDomain = DomainList[domain]; + return true; + } + + Console.WriteLine($"Unable to find domain: {domain}"); + return false; + } + catch // Just in case + { + Console.WriteLine($"Unable to find domain: {domain}"); + } + + return false; + } + + public string HashRegion(int addr, int count, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + + // checks + if (addr < 0 || addr >= d.Size) + { + string error = $"Address {addr} is outside the bounds of domain {d.Name}"; + Console.WriteLine(error); + throw new ArgumentOutOfRangeException(error); + } + if (addr + count > d.Size) + { + string error = $"Address {addr} + count {count} is outside the bounds of domain {d.Name}"; + Console.WriteLine(error); + throw new ArgumentOutOfRangeException(error); + } + + byte[] data = new byte[count]; + for (int i = 0; i < count; i++) + { + data[i] = d.PeekByte(addr + i); + } + + using (var hasher = System.Security.Cryptography.SHA256.Create()) + { + return hasher.ComputeHash(data).BytesToHexString(); + } + } + + #endregion + + #region Endian Handling + + private int ReadSigned(int addr, int size, string domain = null) + { + if (_isBigEndian) return ReadSignedBig(addr, size, domain); + else return ReadSignedLittle(addr, size, domain); + } + + private uint ReadUnsigned(int addr, int size, string domain = null) + { + if (_isBigEndian) return ReadUnsignedBig(addr, size, domain); + else return ReadUnsignedLittle(addr, size, domain); + } + + private void WriteSigned(int addr, int value, int size, string domain = null) + { + if (_isBigEndian) WriteSignedBig(addr, value, size, domain); + else WriteSignedLittle(addr, value, size, domain); + } + + private void WriteUnsigned(int addr, uint value, int size, string domain = null) + { + if (_isBigEndian) WriteUnsignedBig(addr, value, size, domain); + else WriteUnsignedLittle(addr, value, size, domain); + } + + #endregion + + #region Common Special and Legacy Methods + + public uint ReadByte(int addr, string domain = null) + { + return ReadUnsignedByte(addr, domain); + } + + public void WriteByte(int addr, uint value, string domain = null) + { + WriteUnsignedByte(addr, value, domain); + } + + public new List ReadByteRange(int addr, int length, string domain = null) + { + return base.ReadByteRange(addr, length, domain); + } + + public new void WriteByteRange(int addr, List memoryblock, string domain = null) + { + base.WriteByteRange(addr, memoryblock, domain); + } + + public float ReadFloat(int addr, string domain = null) + { + return base.ReadFloat(addr, _isBigEndian, domain); + } + + public void WriteFloat(int addr, double value, string domain = null) + { + base.WriteFloat(addr, value, _isBigEndian, domain); + } + + #endregion + + #region 1 Byte + + public int ReadS8(int addr, string domain = null) + { + return (sbyte)ReadUnsignedByte(addr, domain); + } + + public void WriteS8(int addr, uint value, string domain = null) + { + WriteUnsignedByte(addr, value, domain); + } + + public uint ReadU8(int addr, string domain = null) + { + return ReadUnsignedByte(addr, domain); + } + + public void WriteU8(int addr, uint value, string domain = null) + { + WriteUnsignedByte(addr, value, domain); + } + + #endregion + + #region 2 Byte + public int ReadS16(int addr, string domain = null) + { + return ReadSigned(addr, 2, domain); + } + + public void WriteS16(int addr, int value, string domain = null) + { + WriteSigned(addr, value, 2, domain); + } + + public uint ReadU16(int addr, string domain = null) + { + return ReadUnsigned(addr, 2, domain); + } + + public void WriteU16(int addr, uint value, string domain = null) + { + WriteUnsigned(addr, value, 2, domain); + } + #endregion + + #region 3 Byte + + public int ReadS24(int addr, string domain = null) + { + return ReadSigned(addr, 3, domain); + } + public void WriteS24(int addr, int value, string domain = null) + { + WriteSigned(addr, value, 3, domain); + } + + public uint ReadU24(int addr, string domain = null) + { + return ReadUnsigned(addr, 3, domain); + } + + public void WriteU24(int addr, uint value, string domain = null) + { + WriteUnsigned(addr, value, 3, domain); + } + + #endregion + + #region 4 Byte + + public int ReadS32(int addr, string domain = null) + { + return ReadSigned(addr, 4, domain); + } + + public void WriteS32(int addr, int value, string domain = null) + { + WriteSigned(addr, value, 4, domain); + } + + public uint ReadU32(int addr, string domain = null) + { + return ReadUnsigned(addr, 4, domain); + } + + public void WriteU32(int addr, uint value, string domain = null) + { + WriteUnsigned(addr, value, 4, domain); + } + + #endregion + } +} \ No newline at end of file diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs b/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs new file mode 100644 index 0000000000..f0916a518a --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public sealed class MemorySavestatePluginLibrary + { + public MemorySavestatePluginLibrary() + { } + + [RequiredService] + private IStatable StatableCore { get; set; } + + private readonly Dictionary _memorySavestates = new Dictionary(); + + public string SaveCoreStateToMemory() + { + var guid = Guid.NewGuid(); + var bytes = (byte[])StatableCore.SaveStateBinary().Clone(); + + _memorySavestates.Add(guid, bytes); + + return guid.ToString(); + } + + public void LoadCoreStateFromMemory(string identifier) + { + var guid = new Guid(identifier); + + try + { + var state = _memorySavestates[guid]; + + using (var ms = new MemoryStream(state)) + using (var br = new BinaryReader(ms)) + { + StatableCore.LoadStateBinary(br); + } + } + catch + { + Console.WriteLine("Unable to find the given savestate in memory"); + } + } + + public void DeleteState(string identifier) + { + var guid = new Guid(identifier); + _memorySavestates.Remove(guid); + } + + public void ClearInMemoryStates() + { + _memorySavestates.Clear(); + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs new file mode 100644 index 0000000000..6673f561ff --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace BizHawk.Client.Common +{ + public sealed class MoviePluginLibrary + { + public MoviePluginLibrary() + { } + + [LuaMethodExample("if ( movie.startsfromsavestate( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a savestate-anchored movie\" );\r\nend;")] + [LuaMethod("startsfromsavestate", "Returns whether or not the movie is a savestate-anchored movie")] + public bool StartsFromSavestate() + { + return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSavestate; + } + + [LuaMethodExample("if ( movie.startsfromsaveram( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a saveram-anchored movie\" );\r\nend;")] + [LuaMethod("startsfromsaveram", "Returns whether or not the movie is a saveram-anchored movie")] + public bool StartsFromSaveram() + { + return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSaveRam; + } + + [LuaMethodExample("local stmovfil = movie.filename( );")] + [LuaMethod("filename", "Returns the file name including path of the currently loaded movie")] + public static string Filename() + { + return Global.MovieSession.Movie.Filename; + } + + [LuaMethodExample("local nlmovget = movie.getinput( 500 );")] + [LuaMethod("getinput", "Returns a table of buttons pressed on a given frame of the loaded movie")] + public Dictionary GetInput(int frame) + { + if (!Global.MovieSession.Movie.IsActive) + { + Console.WriteLine("No movie loaded"); + return null; + } + + var input = new Dictionary(); + var adapter = Global.MovieSession.Movie.GetInputState(frame); + + if (adapter == null) + { + Console.WriteLine("Can't get input of the last frame of the movie. Use the previous frame"); + return null; + } + + foreach (var button in adapter.Definition.BoolButtons) + { + input[button] = adapter.IsPressed(button); + } + + foreach (var button in adapter.Definition.FloatControls) + { + input[button] = adapter.GetFloat(button); + } + + return input; + } + + [LuaMethodExample("local stmovget = movie.getinputasmnemonic( 500 );")] + [LuaMethod("getinputasmnemonic", "Returns the input of a given frame of the loaded movie in a raw inputlog string")] + public string GetInputAsMnemonic(int frame) + { + if (Global.MovieSession.Movie.IsActive && frame < Global.MovieSession.Movie.InputLogLength) + { + var lg = Global.MovieSession.LogGeneratorInstance(); + lg.SetSource(Global.MovieSession.Movie.GetInputState(frame)); + return lg.GenerateLogEntry(); + } + + return ""; + } + + [LuaMethodExample("if ( movie.getreadonly( ) ) then\r\n\tconsole.log( \"Returns true if the movie is in read-only mode, false if in read+write\" );\r\nend;")] + [LuaMethod("getreadonly", "Returns true if the movie is in read-only mode, false if in read+write")] + public static bool GetReadOnly() + { + return Global.MovieSession.ReadOnly; + } + + [LuaMethodExample("local ulmovget = movie.getrerecordcount();")] + [LuaMethod("getrerecordcount", "Gets the rerecord count of the current movie.")] + public static ulong GetRerecordCount() + { + return Global.MovieSession.Movie.Rerecords; + } + + [LuaMethodExample("if ( movie.getrerecordcounting( ) ) then\r\n\tconsole.log( \"Returns whether or not the current movie is incrementing rerecords on loadstate\" );\r\nend;")] + [LuaMethod("getrerecordcounting", "Returns whether or not the current movie is incrementing rerecords on loadstate")] + public static bool GetRerecordCounting() + { + return Global.MovieSession.Movie.IsCountingRerecords; + } + + [LuaMethodExample("if ( movie.isloaded( ) ) then\r\n\tconsole.log( \"Returns true if a movie is loaded in memory ( play, record, or finished modes ), false if not ( inactive mode )\" );\r\nend;")] + [LuaMethod("isloaded", "Returns true if a movie is loaded in memory (play, record, or finished modes), false if not (inactive mode)")] + public static bool IsLoaded() + { + return Global.MovieSession.Movie.IsActive; + } + + [LuaMethodExample("local domovlen = movie.length( );")] + [LuaMethod("length", "Returns the total number of frames of the loaded movie")] + public static double Length() + { + return Global.MovieSession.Movie.FrameCount; + } + + [LuaMethodExample("local stmovmod = movie.mode( );")] + [LuaMethod("mode", "Returns the mode of the current movie. Possible modes: \"PLAY\", \"RECORD\", \"FINISHED\", \"INACTIVE\"")] + public static string Mode() + { + if (Global.MovieSession.Movie.IsFinished) + { + return "FINISHED"; + } + + if (Global.MovieSession.Movie.IsPlaying) + { + return "PLAY"; + } + + if (Global.MovieSession.Movie.IsRecording) + { + return "RECORD"; + } + + return "INACTIVE"; + } + + [LuaMethodExample("movie.save( \"C:\\moviename.ext\" );")] + [LuaMethod("save", "Saves the current movie to the disc. If the filename is provided (no extension or path needed), the movie is saved under the specified name to the current movie directory. The filename may contain a subdirectory, it will be created if it doesn't exist. Existing files won't get overwritten.")] + public void Save(string filename = "") + { + if (!Global.MovieSession.Movie.IsActive) + { + return; + } + + if (!string.IsNullOrEmpty(filename)) + { + filename += "." + Global.MovieSession.Movie.PreferredExtension; + var test = new FileInfo(filename); + if (test.Exists) + { + Console.WriteLine($"File {filename} already exists, will not overwrite"); + return; + } + + Global.MovieSession.Movie.Filename = filename; + } + + Global.MovieSession.Movie.Save(); + } + + [LuaMethodExample("movie.setreadonly( false );")] + [LuaMethod("setreadonly", "Sets the read-only state to the given value. true for read only, false for read+write")] + public static void SetReadOnly(bool readOnly) + { + Global.MovieSession.ReadOnly = readOnly; + } + + [LuaMethodExample("movie.setrerecordcount( 20.0 );")] + [LuaMethod("setrerecordcount", "Sets the rerecord count of the current movie.")] + public static void SetRerecordCount(double count) + { + // Lua numbers are always double, integer precision holds up + // to 53 bits, so throw an error if it's bigger than that. + const double PrecisionLimit = 9007199254740992d; + + if (count > PrecisionLimit) + { + throw new Exception("Rerecord count exceeds Lua integer precision."); + } + + Global.MovieSession.Movie.Rerecords = (ulong)count; + } + + [LuaMethodExample("movie.setrerecordcounting( true );")] + [LuaMethod("setrerecordcounting", "Sets whether or not the current movie will increment the rerecord counter on loadstate")] + public static void SetRerecordCounting(bool counting) + { + Global.MovieSession.Movie.IsCountingRerecords = counting; + } + + [LuaMethodExample("movie.stop( );")] + [LuaMethod("stop", "Stops the current movie")] + public static void Stop() + { + Global.MovieSession.Movie.Stop(); + } + + [LuaMethodExample("local domovget = movie.getfps( );")] + [LuaMethod("getfps", "If a movie is loaded, gets the frames per second used by the movie to determine the movie length time")] + public static double GetFps() + { + if (Global.MovieSession.Movie.IsActive) + { + var movie = Global.MovieSession.Movie; + var system = movie.HeaderEntries[HeaderKeys.PLATFORM]; + var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) && + movie.HeaderEntries[HeaderKeys.PAL] == "1"; + + return new PlatformFrameRates()[system, pal]; + } + + return 0.0; + } + + [LuaMethodExample("local nlmovget = movie.getheader( );")] + [LuaMethod("getheader", "If a movie is active, will return the movie header as a lua table")] + public Dictionary GetHeader() + { + var table = new Dictionary(); + if (Global.MovieSession.Movie.IsActive) + { + foreach (var kvp in Global.MovieSession.Movie.HeaderEntries) + { + table[kvp.Key] = kvp.Value; + } + } + + return table; + } + + [LuaMethodExample("local nlmovget = movie.getcomments( );")] + [LuaMethod("getcomments", "If a movie is active, will return the movie comments as a lua table")] + public List GetComments() + { + var list = new List(Global.MovieSession.Movie.Comments.Count); + if (Global.MovieSession.Movie.IsActive) + { + for (int i = 0; i < Global.MovieSession.Movie.Comments.Count; i++) + { + list[i] = Global.MovieSession.Movie.Comments[i]; + } + } + + return list; + } + + [LuaMethodExample("local nlmovget = movie.getsubtitles( );")] + [LuaMethod("getsubtitles", "If a movie is active, will return the movie subtitles as a lua table")] + public List GetSubtitles() + { + var list = new List(Global.MovieSession.Movie.Subtitles.Count); + if (Global.MovieSession.Movie.IsActive) + { + for (int i = 0; i < Global.MovieSession.Movie.Subtitles.Count; i++) + { + list[i] = Global.MovieSession.Movie.Subtitles[i].ToString(); + } + } + + return list; + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs new file mode 100644 index 0000000000..1613ac46ce --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs @@ -0,0 +1,52 @@ +using System; +using System.ComponentModel; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class UserDataPluginLibrary + { + public UserDataPluginLibrary() + { } + + public void Set(string name, object value) + { + if (value != null) + { + var t = value.GetType(); + if (!t.IsPrimitive && t != typeof(string)) + { + throw new InvalidOperationException("Invalid type for userdata"); + } + } + + Global.UserBag[name] = value; + } + + public object Get(string key) + { + if (Global.UserBag.ContainsKey(key)) + { + return Global.UserBag[key]; + } + + return null; + } + + public void Clear() + { + Global.UserBag.Clear(); + } + + public bool Remove(string key) + { + return Global.UserBag.Remove(key); + } + + public bool ContainsKey(string key) + { + return Global.UserBag.ContainsKey(key); + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginMemoryBase.cs b/BizHawk.Client.Common/plugins/PluginMemoryBase.cs new file mode 100644 index 0000000000..92bfad1a81 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginMemoryBase.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Client.Common +{ + /// + /// Base class for the Memory and MainMemory plugin libraries + /// + public abstract class PluginMemoryBase + { + [RequiredService] + protected IEmulator Emulator { get; set; } + + [OptionalService] + protected IMemoryDomains MemoryDomainCore { get; set; } + + protected abstract MemoryDomain Domain { get; } + + protected PluginMemoryBase() + { + + } + + protected IMemoryDomains DomainList + { + get + { + if (MemoryDomainCore != null) + { + return MemoryDomainCore; + } + + var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains"; + Console.WriteLine(error); + throw new NotImplementedException(error); + } + } + + public string VerifyMemoryDomain(string domain) + { + try + { + if (DomainList[domain] == null) + { + Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); + return Domain.Name; + } + + return domain; + } + catch // Just in case + { + Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); + } + + return Domain.Name; + } + + protected uint ReadUnsignedByte(int addr, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (addr < d.Size) + { + return d.PeekByte(addr); + } + + Console.WriteLine("Warning: attempted read of " + addr + " outside the memory size of " + d.Size); + return 0; + } + + protected void WriteUnsignedByte(int addr, uint v, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + if (addr < d.Size) + { + d.PokeByte(addr, (byte)v); + } + else + { + Console.WriteLine("Warning: attempted write to " + addr + " outside the memory size of " + d.Size); + } + } + else + { + Console.WriteLine($"Error: the domain {d.Name} is not writable"); + } + } + + protected static int U2S(uint u, int size) + { + var s = (int)u; + s <<= 8 * (4 - size); + s >>= 8 * (4 - size); + return s; + } + + protected int ReadSignedLittle(int addr, int size, string domain = null) + { + return U2S(ReadUnsignedLittle(addr, size, domain), size); + } + + protected uint ReadUnsignedLittle(int addr, int size, string domain = null) + { + uint v = 0; + for (var i = 0; i < size; ++i) + { + v |= ReadUnsignedByte(addr + i, domain) << (8 * i); + } + + return v; + } + + protected int ReadSignedBig(int addr, int size, string domain = null) + { + return U2S(ReadUnsignedBig(addr, size, domain), size); + } + + protected uint ReadUnsignedBig(int addr, int size, string domain = null) + { + uint v = 0; + for (var i = 0; i < size; ++i) + { + v |= ReadUnsignedByte(addr + i, domain) << (8 * (size - 1 - i)); + } + + return v; + } + + protected void WriteSignedLittle(int addr, int v, int size, string domain = null) + { + WriteUnsignedLittle(addr, (uint)v, size, domain); + } + + protected void WriteUnsignedLittle(int addr, uint v, int size, string domain = null) + { + for (var i = 0; i < size; ++i) + { + WriteUnsignedByte(addr + i, (v >> (8 * i)) & 0xFF, domain); + } + } + + protected void WriteSignedBig(int addr, int v, int size, string domain = null) + { + WriteUnsignedBig(addr, (uint)v, size, domain); + } + + protected void WriteUnsignedBig(int addr, uint v, int size, string domain = null) + { + for (var i = 0; i < size; ++i) + { + WriteUnsignedByte(addr + i, (v >> (8 * (size - 1 - i))) & 0xFF, domain); + } + } + + #region public Library implementations + + protected List ReadByteRange(int addr, int length, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + var lastAddr = length + addr; + var list = new List(); + for (; addr <= lastAddr; addr++) + { + if (addr < d.Size) + list.Add(d.PeekByte(addr)); + else { + Console.WriteLine("Warning: Attempted read " + addr + " outside memory domain size of " + d.Size + " in readbyterange()"); + list.Add(0); + } + } + + return list; + } + + protected void WriteByteRange(int addr, List memoryblock, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + for (var i = 0; i < memoryblock.Count; i++) + { + if (addr < d.Size) + { + d.PokeByte(addr++, memoryblock[i]); + } + else + { + Console.WriteLine("Warning: Attempted write " + addr + " outside memory domain size of " + d.Size + " in writebyterange()"); + } + } + } + else + { + Console.WriteLine($"Error: the domain {d.Name} is not writable"); + } + } + + protected float ReadFloat(int addr, bool bigendian, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (addr < d.Size) + { + var val = d.PeekUint(addr, bigendian); + var bytes = BitConverter.GetBytes(val); + return BitConverter.ToSingle(bytes, 0); + } + + Console.WriteLine("Warning: Attempted read " + addr + " outside memory size of " + d.Size); + + return 0; + } + + protected void WriteFloat(int addr, double value, bool bigendian, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + if (addr < d.Size) + { + var dv = (float)value; + var bytes = BitConverter.GetBytes(dv); + var v = BitConverter.ToUInt32(bytes, 0); + d.PokeUint(addr, v, bigendian); + } + else + { + Console.WriteLine("Warning: Attempted write " + addr + " outside memory size of " + d.Size); + } + } + else + { + Console.WriteLine($"Error: the domain {Domain.Name} is not writable"); + } + } + + #endregion + } +} diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index a5b9eaf9d6..9161107c04 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -634,6 +634,8 @@ + + diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs new file mode 100644 index 0000000000..71e0d1ec6f --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using System.IO; + +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class GUIDrawLibrary : GUIDrawPluginLibrary + { + public GUIDrawLibrary() + { + } + + private DisplaySurface _GUISurface = null; + + #region Gui API + + public override void DrawNew(string name, bool? clear = true) + { + try + { + DrawFinish(); + _GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true); + HasGUISurface = (_GUISurface != null); + + } + catch (InvalidOperationException ex) + { + Console.WriteLine(ex.ToString()); + } + } + + public override void DrawFinish() + { + if (_GUISurface != null) + { + GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface); + } + + _GUISurface = null; + HasGUISurface = false; + + } + #endregion + + #region Helpers + protected override Graphics GetGraphics() + { + var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics(); + + // we don't like CoreComm, right? Someone should find a different way to do this then. + var tx = Emulator.CoreComm.ScreenLogicalOffsetX; + var ty = Emulator.CoreComm.ScreenLogicalOffsetY; + if (tx != 0 || ty != 0) + { + var transform = g.Transform; + transform.Translate(-tx, -ty); + g.Transform = transform; + } + + return g; + } + #endregion + + public override void AddMessage(string message) + { + GlobalWin.OSD.AddMessage(message); + } + + public override void ClearGraphics() + { + _GUISurface.Clear(); + DrawFinish(); + } + + public override void ClearText() + { + GlobalWin.OSD.ClearGUIText(); + } + + public override void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null) + { + using (var g = GetGraphics()) + { + try + { + var index = 0; + if (string.IsNullOrEmpty(fontfamily)) + { + index = _defaultPixelFont; + } + else + { + switch (fontfamily) + { + case "fceux": + case "0": + index = 0; + break; + case "gens": + case "1": + index = 1; + break; + default: + Console.WriteLine($"Unable to find font family: {fontfamily}"); + return; + } + } + + var f = new StringFormat(StringFormat.GenericTypographic) + { + FormatFlags = StringFormatFlags.MeasureTrailingSpaces + }; + var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel); + Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize(); + var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0)); + g.FillRectangle(GetBrush(backcolor ?? _defaultTextBackground.Value), rect); + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; + g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y); + } + catch (Exception) + { + return; + } + } + } + + public override void Text(int x, int y, string message, Color? forecolor = null, string anchor = null) + { + var a = 0; + + if (!string.IsNullOrEmpty(anchor)) + { + switch (anchor) + { + case "0": + case "topleft": + a = 0; + break; + case "1": + case "topright": + a = 1; + break; + case "2": + case "bottomleft": + a = 2; + break; + case "3": + case "bottomright": + a = 3; + break; + } + } + else + { + x -= Emulator.CoreComm.ScreenLogicalOffsetX; + y -= Emulator.CoreComm.ScreenLogicalOffsetY; + } + + GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a); + } + } +} \ No newline at end of file From bb020540eb9dd207f0998104bae11977446b9d60 Mon Sep 17 00:00:00 2001 From: upthorn Date: Fri, 31 Aug 2018 21:26:38 -0700 Subject: [PATCH 002/440] Remove extraneous non-existent file/folders from project. --- BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj | 1 - BizHawk.sln | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 9161107c04..e4d50eb1de 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -635,7 +635,6 @@ - diff --git a/BizHawk.sln b/BizHawk.sln index 63b4c5be18..2b1a0659ef 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2047 MinimumVisualStudioVersion = 12.0.31101.0 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Version", "Version\Version.csproj", "{0CE8B337-08E3-4602-BF10-C4D4C75D2F13}" EndProject @@ -145,6 +144,9 @@ Global {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1A77376C-2741-489C-90E1-03E415910B65} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = BizHawk.Client.EmuHawk\BizHawk.Client.EmuHawk.csproj EndGlobalSection From 0a6aa912cfa1891176b8316ba5dd91cbd4f66a90 Mon Sep 17 00:00:00 2001 From: upthorn Date: Sat, 1 Sep 2018 03:19:05 -0700 Subject: [PATCH 003/440] Further plugin interface design/development work --- .../BizHawk.Client.Common.csproj | 2 + BizHawk.Client.Common/plugins/IPlugin.cs | 12 ++ BizHawk.Client.Common/plugins/IPluginAPI.cs | 23 ++++ BizHawk.Client.Common/plugins/PluginBase.cs | 43 +----- .../plugins/PluginLibrary.MemoryEvents.cs | 45 ++++++ .../plugins/PluginLibrary.SQL.cs | 130 ++++++++++++++++++ .../plugins/PluginLibrary.UserData.cs | 2 +- .../plugins/PluginLibraryBase.cs | 30 ++++ ...GUIDrawLibrary.cs => Plugin.GUILibrary.cs} | 8 +- 9 files changed, 247 insertions(+), 48 deletions(-) create mode 100644 BizHawk.Client.Common/plugins/IPlugin.cs create mode 100644 BizHawk.Client.Common/plugins/IPluginAPI.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs create mode 100644 BizHawk.Client.Common/plugins/PluginLibraryBase.cs rename BizHawk.Client.EmuHawk/Plugins/Libraries/{GUIDrawLibrary.cs => Plugin.GUILibrary.cs} (95%) diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 18110a72f2..65c07d9649 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -137,8 +137,10 @@ + + diff --git a/BizHawk.Client.Common/plugins/IPlugin.cs b/BizHawk.Client.Common/plugins/IPlugin.cs new file mode 100644 index 0000000000..9220e90dbd --- /dev/null +++ b/BizHawk.Client.Common/plugins/IPlugin.cs @@ -0,0 +1,12 @@ +namespace BizHawk.Client.Common +{ + interface IPlugin + { + void PreFrameCallback(); + void PostFrameCallback(); + void SaveStateCallback(string name); + void LoadStateCallback(string name); + void InputPollCallback(); + void Init(IPluginAPI api); + } +} diff --git a/BizHawk.Client.Common/plugins/IPluginAPI.cs b/BizHawk.Client.Common/plugins/IPluginAPI.cs new file mode 100644 index 0000000000..786858d96a --- /dev/null +++ b/BizHawk.Client.Common/plugins/IPluginAPI.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Client.Common +{ + interface IPluginAPI + { + EmulatorPluginLibrary EmuLib { get; set; } + GameInfoPluginLibrary GameInfoLib { get; set; } + GUIDrawPluginLibrary GuiLib { get; set; } + JoypadPluginLibrary JoypadLib { get; set; } + MemoryPluginLibrary MemLib { get; set; } + MemoryEventsPluginLibrary MemEventsLib { get; set; } + MemorySavestatePluginLibrary MemStateLib { get; set; } + MoviePluginLibrary MovieLib { get; set; } + SQLPluginLibrary SQLLib { get; set; } + UserDataPluginLibrary UserDataLib { get; set; } + List ClientLibs { get; set; } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginBase.cs b/BizHawk.Client.Common/plugins/PluginBase.cs index 44f88da68c..1e457e94f4 100644 --- a/BizHawk.Client.Common/plugins/PluginBase.cs +++ b/BizHawk.Client.Common/plugins/PluginBase.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public abstract class PluginBase + public abstract class PluginBase : IPlugin { [RequiredService] private IEmulator Emulator { get; set; } @@ -19,40 +15,5 @@ namespace BizHawk.Client.Common [OptionalService] private IDebuggable DebuggableCore { get; set; } - - public abstract void PreFrameCallback(); - public abstract void PostFrameCallback(); - public abstract void SaveStateCallback(string name); - public abstract void LoadStateCallback(string name); - public abstract void InputPollCallback(); - - protected virtual void AddReadCallback(Action cb, uint address, string domain) - { - if (DebuggableCore.MemoryCallbacksAvailable()) - { - DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Read, "Lua Hook", cb, address, null)); - } - } - protected virtual void AddWriteCallback(Action cb, uint address, string domain) - { - if (DebuggableCore.MemoryCallbacksAvailable()) - { - DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Write, "Lua Hook", cb, address, null)); - } - } - protected virtual void AddExecCallback(Action cb, uint address, string domain) - { - if (DebuggableCore.MemoryCallbacksAvailable() && DebuggableCore.MemoryCallbacks.ExecuteCallbacksAvailable) - { - DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Execute, "Lua Hook", cb, address, null)); - } - } - protected virtual void RemoveMemoryCallback(Action cb) - { - if (DebuggableCore.MemoryCallbacksAvailable()) - { - DebuggableCore.MemoryCallbacks.Remove(cb); - } - } } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs b/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs new file mode 100644 index 0000000000..12dfc1ab3f --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs @@ -0,0 +1,45 @@ +using System; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Client.Common +{ + public sealed class MemoryEventsPluginLibrary + { + [RequiredService] + private IDebuggable DebuggableCore { get; set; } + + public MemoryEventsPluginLibrary () + { } + + public void AddReadCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Read, "Plugin Hook", cb, address, null)); + } + } + public void AddWriteCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Write, "Plugin Hook", cb, address, null)); + } + } + public void AddExecCallback(Action cb, uint address, string domain) + { + if (DebuggableCore.MemoryCallbacksAvailable() && DebuggableCore.MemoryCallbacks.ExecuteCallbacksAvailable) + { + DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Execute, "Plugin Hook", cb, address, null)); + } + } + public void RemoveMemoryCallback(Action cb) + { + if (DebuggableCore.MemoryCallbacksAvailable()) + { + DebuggableCore.MemoryCallbacks.Remove(cb); + } + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs b/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs new file mode 100644 index 0000000000..5271b82219 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data.SQLite; + +namespace BizHawk.Client.Common +{ + public sealed class SQLPluginLibrary + { + public SQLPluginLibrary() + { } + + SQLiteConnection m_dbConnection; + string connectionString; + + public string CreateDatabase(string name) + { + try + { + SQLiteConnection.CreateFile(name); + return "Database Created Successfully"; + } + catch (SQLiteException sqlEX) + { + return sqlEX.Message; + } + + } + + public string OpenDatabase(string name) + { + try + { + SQLiteConnectionStringBuilder connBuilder = new SQLiteConnectionStringBuilder(); + connBuilder.DataSource = name; + connBuilder.Version = 3; //SQLite version + connBuilder.JournalMode = SQLiteJournalModeEnum.Wal; //Allows for reads and writes to happen at the same time + connBuilder.DefaultIsolationLevel = System.Data.IsolationLevel.ReadCommitted; //This only helps make the database lock left. May be pointless now + connBuilder.SyncMode = SynchronizationModes.Off; //This shortens the delay for do synchronous calls. + m_dbConnection = new SQLiteConnection(connBuilder.ToString()); + connectionString = connBuilder.ToString(); + m_dbConnection.Open(); + m_dbConnection.Close(); + return "Database Opened Successfully"; + } + catch (SQLiteException sqlEX) + { + return sqlEX.Message; + } + } + + public string WriteCommand(string query = "") + { + if (query == "") + { + return "query is empty"; + } + try + { + m_dbConnection.Open(); + string sql = query; + SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); + command.ExecuteNonQuery(); + m_dbConnection.Close(); + + return "Command ran successfully"; + + } + catch (NullReferenceException nullEX) + { + return "Database not open."; + } + catch (SQLiteException sqlEX) + { + m_dbConnection.Close(); + return sqlEX.Message; + } + } + + public dynamic ReadCommand(string query = "") + { + if (query == "") + { + return "query is empty"; + } + try + { + var table = new Dictionary(); + m_dbConnection.Open(); + string sql = "PRAGMA read_uncommitted =1;" + query; + SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); + SQLiteDataReader reader = command.ExecuteReader(); + bool rows = reader.HasRows; + long rowCount = 0; + var columns = new List(); + for (int i = 0; i < reader.FieldCount; ++i) //Add all column names into list + { + columns.Add(reader.GetName(i)); + } + while (reader.Read()) + { + for (int i = 0; i < reader.FieldCount; ++i) + { + table[columns[i] + " " + rowCount.ToString()] = reader.GetValue(i); + } + rowCount += 1; + } + reader.Close(); + m_dbConnection.Close(); + if (rows == false) + { + return "No rows found"; + } + + return table; + + } + catch (NullReferenceException) + { + return "Database not opened."; + } + catch (SQLiteException sqlEX) + { + m_dbConnection.Close(); + return sqlEX.Message; + } + } + + } +} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs index 1613ac46ce..3d60ad8fb1 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using BizHawk.Client.Common; -namespace BizHawk.Client.EmuHawk +namespace BizHawk.Client.Common { public sealed class UserDataPluginLibrary { diff --git a/BizHawk.Client.Common/plugins/PluginLibraryBase.cs b/BizHawk.Client.Common/plugins/PluginLibraryBase.cs new file mode 100644 index 0000000000..c480871c69 --- /dev/null +++ b/BizHawk.Client.Common/plugins/PluginLibraryBase.cs @@ -0,0 +1,30 @@ +using System.Drawing; + +namespace BizHawk.Client.Common +{ + public abstract class PluginLibraryBase + { + protected PluginLibraryBase() { } + public abstract string Name { get; } + + protected static Color? ToColor(object o) + { + if (o == null) + { + return null; + } + + if (o.GetType() == typeof(double)) + { + return Color.FromArgb((int)(long)(double)o); + } + + if (o.GetType() == typeof(string)) + { + return Color.FromName(o.ToString()); + } + + return null; + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs similarity index 95% rename from BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs rename to BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs index 71e0d1ec6f..90b6ddba27 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/GUIDrawLibrary.cs +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs @@ -1,17 +1,13 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.Windows.Forms; -using System.IO; -using BizHawk.Emulation.Common; using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public sealed class GUIDrawLibrary : GUIDrawPluginLibrary + public sealed class GUIPluginLibrary : GUIDrawPluginLibrary { - public GUIDrawLibrary() + public GUIPluginLibrary() { } From 9e814896cb68cdc7de91b7f46f7d1eb418c400e1 Mon Sep 17 00:00:00 2001 From: upthorn Date: Mon, 3 Sep 2018 19:31:01 -0700 Subject: [PATCH 004/440] Some plugin interface libraries, and further refactoring. --- .../BizHawk.Client.Common.csproj | 3 + BizHawk.Client.Common/plugins/IPluginAPI.cs | 27 +- BizHawk.Client.Common/plugins/PluginBase.cs | 47 ++- .../plugins/PluginLibrary.Emu.cs | 4 +- .../plugins/PluginLibrary.GUIDraw.cs | 27 +- .../plugins/PluginLibrary.Gameinfo.cs | 4 +- .../plugins/PluginLibrary.Joypad.cs | 44 ++- .../plugins/PluginLibrary.Memory.cs | 69 ++-- .../plugins/PluginLibrary.MemoryEvents.cs | 4 +- .../plugins/PluginLibrary.MemorySavestate.cs | 6 +- .../plugins/PluginLibrary.Movie.cs | 4 +- .../plugins/PluginLibrary.SQL.cs | 4 +- .../plugins/PluginLibrary.UserData.cs | 4 +- .../plugins/PluginLibraryBase.cs | 1 - .../plugins/PluginMemoryBase.cs | 36 +- .../Plugins/Libraries/PluginLibrary.Client.cs | 351 ++++++++++++++++++ .../Libraries/PluginLibrary.Communications.cs | 121 ++++++ ...gin.GUILibrary.cs => PluginLibrary.GUI.cs} | 9 +- .../Plugins/Libraries/PluginLibrary.Input.cs | 43 +++ .../Libraries/PluginLibrary.Savestate.cs | 47 +++ .../Plugins/Libraries/PluginLibrary.cs | 135 +++++++ BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs | 28 ++ 22 files changed, 904 insertions(+), 114 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs rename BizHawk.Client.EmuHawk/Plugins/Libraries/{Plugin.GUILibrary.cs => PluginLibrary.GUI.cs} (95%) create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs create mode 100644 BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs create mode 100644 BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 65c07d9649..f3bcc12f20 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -132,6 +132,8 @@ + + @@ -142,6 +144,7 @@ + diff --git a/BizHawk.Client.Common/plugins/IPluginAPI.cs b/BizHawk.Client.Common/plugins/IPluginAPI.cs index 786858d96a..175df3af92 100644 --- a/BizHawk.Client.Common/plugins/IPluginAPI.cs +++ b/BizHawk.Client.Common/plugins/IPluginAPI.cs @@ -1,23 +1,20 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BizHawk.Client.Common { - interface IPluginAPI + public interface IPluginAPI { - EmulatorPluginLibrary EmuLib { get; set; } - GameInfoPluginLibrary GameInfoLib { get; set; } - GUIDrawPluginLibrary GuiLib { get; set; } - JoypadPluginLibrary JoypadLib { get; set; } - MemoryPluginLibrary MemLib { get; set; } - MemoryEventsPluginLibrary MemEventsLib { get; set; } - MemorySavestatePluginLibrary MemStateLib { get; set; } - MoviePluginLibrary MovieLib { get; set; } - SQLPluginLibrary SQLLib { get; set; } - UserDataPluginLibrary UserDataLib { get; set; } - List ClientLibs { get; set; } + EmulatorPluginLibrary EmuLib { get; } + GameInfoPluginLibrary GameInfoLib { get; } + GUIDrawPluginBase GUILib { get; } + JoypadPluginLibrary JoypadLib { get; } + MemoryPluginLibrary MemLib { get; } + MemoryEventsPluginLibrary MemEventsLib { get; } + MemorySavestatePluginLibrary MemStateLib { get; } + MoviePluginLibrary MovieLib { get; } + SQLPluginLibrary SQLLib { get; } + UserDataPluginLibrary UserDataLib { get; } + Dictionary Libraries { get; } } } diff --git a/BizHawk.Client.Common/plugins/PluginBase.cs b/BizHawk.Client.Common/plugins/PluginBase.cs index 1e457e94f4..7ef2f4453d 100644 --- a/BizHawk.Client.Common/plugins/PluginBase.cs +++ b/BizHawk.Client.Common/plugins/PluginBase.cs @@ -4,16 +4,47 @@ namespace BizHawk.Client.Common { public abstract class PluginBase : IPlugin { - [RequiredService] - private IEmulator Emulator { get; set; } + /// + /// The base class from which all + /// plugins will be derived + /// + /// Actual plugins should implement + /// one of the below callback methods + /// or register memory callbacks in + /// their Init function. + /// + protected IPluginAPI _api; - [RequiredService] - private IMemoryDomains Domains { get; set; } + public PluginBase() { } - [OptionalService] - private IInputPollable InputPollableCore { get; set; } + public abstract string Name { get; } + public abstract string Description { get; } + + public bool Enabled => Running; + public bool Paused => !Running; - [OptionalService] - private IDebuggable DebuggableCore { get; set; } + public bool Running { get; set; } + + public void Stop() + { + Running = false; + } + + public void Toggle() + { + Running = !Running; + } + + public virtual void PreFrameCallback() { } + public virtual void PostFrameCallback() { } + public virtual void SaveStateCallback(string name) { } + public virtual void LoadStateCallback(string name) { } + public virtual void InputPollCallback() { } + public virtual void ExitCallback() { } + public virtual void Init (IPluginAPI api) + { + _api = api; + Running = true; + } } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs index eb3dd485b9..b205516989 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs @@ -15,7 +15,7 @@ using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; namespace BizHawk.Client.Common { [Description("A library for interacting with the currently loaded emulator core")] - public sealed class EmulatorPluginLibrary + public sealed class EmulatorPluginLibrary : PluginLibraryBase { [RequiredService] private IEmulator Emulator { get; set; } @@ -41,7 +41,7 @@ namespace BizHawk.Client.Common public Action FrameAdvanceCallback { get; set; } public Action YieldCallback { get; set; } - public EmulatorPluginLibrary() + public EmulatorPluginLibrary() : base() { } public static void DisplayVsync(bool enabled) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs index 46081390d2..e6612ad7f7 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs @@ -8,15 +8,13 @@ using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public abstract class GUIDrawPluginLibrary + public abstract class GUIDrawPluginBase : PluginLibraryBase { [RequiredService] protected IEmulator Emulator { get; set; } - public GUIDrawPluginLibrary() - { - - } + public GUIDrawPluginBase() : base() + { } public bool HasGUISurface = false; @@ -166,32 +164,36 @@ namespace BizHawk.Client.Common { try { + float w; + float h; if (x < x2) { - x2 = Math.Abs(x - x2); + w = x2 - x; } else { x2 = x - x2; x -= x2; + w = Math.Max(x2, 0.1f); } if (y < y2) { - y2 = Math.Abs(y - y2); + h = y2 - y; } else { y2 = y - y2; y -= y2; + h = Math.Max(y2, 0.1f); } - g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, x2, y2); + g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, w, h); var bg = background ?? _defaultBackground; if (bg.HasValue) { - g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, x2 - 1, y2 - 1); + g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0)); } } catch (Exception) @@ -389,12 +391,13 @@ namespace BizHawk.Client.Common { using (var g = GetGraphics()) { - g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, width, height); + var w = Math.Max(width, 0.1F); + var h = Math.Max(height, 0.1F); + g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, w, h); var bg = background ?? _defaultBackground; if (bg.HasValue) { - g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, width - 1, height - 1); - } + g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0)); } } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs index 6c9c21b070..e74ea5f21b 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs @@ -5,12 +5,12 @@ using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public sealed class GameInfoPluginLibrary + public sealed class GameInfoPluginLibrary : PluginLibraryBase { [OptionalService] private IBoardInfo BoardInfo { get; set; } - public GameInfoPluginLibrary() + public GameInfoPluginLibrary() : base() { } public string GetRomName() diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs index e981b0ef31..f09a1e5cb1 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs @@ -3,9 +3,10 @@ using System.Collections.Generic; namespace BizHawk.Client.Common { - public sealed class JoypadPluginLibrary + public sealed class JoypadPluginLibrary : PluginLibraryBase { - public JoypadPluginLibrary() { } + public JoypadPluginLibrary() : base() + { } public Dictionary Get(int? controller = null) { @@ -82,8 +83,6 @@ namespace BizHawk.Client.Common } } - [LuaMethodExample("joypad.set( { [\"Left\"] = true, [ \"A\" ] = true, [ \"B\" ] = true } );")] - [LuaMethod("set", "sets the given buttons to their provided values for the current frame")] public void Set(Dictionary buttons, int? controller = null) { try @@ -146,9 +145,24 @@ namespace BizHawk.Client.Common /*Eat it*/ } } + public void Set(string button, bool state, int? controller = null) + { + try + { + var toPress = button; + if (controller.HasValue) + { + toPress = "P" + controller + " " + button; + } - [LuaMethodExample("joypad.setanalog( { [ \"Tilt X\" ] = true, [ \"Tilt Y\" ] = false } );")] - [LuaMethod("setanalog", "sets the given analog controls to their provided values for the current frame. Note that unlike set() there is only the logic of overriding with the given value.")] + Global.LuaAndAdaptor.SetButton(toPress, state); + Global.ActiveController.Overrides(Global.LuaAndAdaptor); + } + catch + { + /*Eat it*/ + } + } public void SetAnalog(Dictionary controls, object controller = null) { try @@ -182,5 +196,23 @@ namespace BizHawk.Client.Common /*Eat it*/ } } + public void SetAnalog(string control, float value, object controller = null) + { + try + { + if (controller == null) + { + Global.StickyXORAdapter.SetFloat(control, value); + } + else + { + Global.StickyXORAdapter.SetFloat("P" + controller + " " + control, value); + } + } + catch + { + /*Eat it*/ + } + } } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs index aa9daf90d3..543ea1780b 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs @@ -10,11 +10,14 @@ namespace BizHawk.Client.Common public sealed class MemoryPluginLibrary : PluginMemoryBase { private MemoryDomain _currentMemoryDomain; - private bool _isBigEndian; - public MemoryPluginLibrary(bool Big = false) + private bool _isBigEndian = false; + public MemoryPluginLibrary() : base() { - _isBigEndian = Big; + } + public void SetBigEndian() + { + _isBigEndian = true; } protected override MemoryDomain Domain @@ -94,7 +97,7 @@ namespace BizHawk.Client.Common return false; } - public string HashRegion(int addr, int count, string domain = null) + public string HashRegion(long addr, int count, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; @@ -128,25 +131,25 @@ namespace BizHawk.Client.Common #region Endian Handling - private int ReadSigned(int addr, int size, string domain = null) + private int ReadSigned(long addr, int size, string domain = null) { if (_isBigEndian) return ReadSignedBig(addr, size, domain); else return ReadSignedLittle(addr, size, domain); } - private uint ReadUnsigned(int addr, int size, string domain = null) + private uint ReadUnsigned(long addr, int size, string domain = null) { if (_isBigEndian) return ReadUnsignedBig(addr, size, domain); else return ReadUnsignedLittle(addr, size, domain); } - private void WriteSigned(int addr, int value, int size, string domain = null) + private void WriteSigned(long addr, int value, int size, string domain = null) { if (_isBigEndian) WriteSignedBig(addr, value, size, domain); else WriteSignedLittle(addr, value, size, domain); } - private void WriteUnsigned(int addr, uint value, int size, string domain = null) + private void WriteUnsigned(long addr, uint value, int size, string domain = null) { if (_isBigEndian) WriteUnsignedBig(addr, value, size, domain); else WriteUnsignedLittle(addr, value, size, domain); @@ -156,32 +159,32 @@ namespace BizHawk.Client.Common #region Common Special and Legacy Methods - public uint ReadByte(int addr, string domain = null) + public uint ReadByte(long addr, string domain = null) { return ReadUnsignedByte(addr, domain); } - public void WriteByte(int addr, uint value, string domain = null) + public void WriteByte(long addr, uint value, string domain = null) { WriteUnsignedByte(addr, value, domain); } - public new List ReadByteRange(int addr, int length, string domain = null) + public new List ReadByteRange(long addr, int length, string domain = null) { return base.ReadByteRange(addr, length, domain); } - public new void WriteByteRange(int addr, List memoryblock, string domain = null) + public new void WriteByteRange(long addr, List memoryblock, string domain = null) { base.WriteByteRange(addr, memoryblock, domain); } - public float ReadFloat(int addr, string domain = null) + public float ReadFloat(long addr, string domain = null) { return base.ReadFloat(addr, _isBigEndian, domain); } - public void WriteFloat(int addr, double value, string domain = null) + public void WriteFloat(long addr, double value, string domain = null) { base.WriteFloat(addr, value, _isBigEndian, domain); } @@ -190,22 +193,22 @@ namespace BizHawk.Client.Common #region 1 Byte - public int ReadS8(int addr, string domain = null) + public int ReadS8(long addr, string domain = null) { return (sbyte)ReadUnsignedByte(addr, domain); } - public void WriteS8(int addr, uint value, string domain = null) + public void WriteS8(long addr, uint value, string domain = null) { WriteUnsignedByte(addr, value, domain); } - public uint ReadU8(int addr, string domain = null) + public uint ReadU8(long addr, string domain = null) { - return ReadUnsignedByte(addr, domain); + return (byte)ReadUnsignedByte(addr, domain); } - public void WriteU8(int addr, uint value, string domain = null) + public void WriteU8(long addr, uint value, string domain = null) { WriteUnsignedByte(addr, value, domain); } @@ -213,22 +216,22 @@ namespace BizHawk.Client.Common #endregion #region 2 Byte - public int ReadS16(int addr, string domain = null) + public int ReadS16(long addr, string domain = null) { - return ReadSigned(addr, 2, domain); + return (short)ReadSigned(addr, 2, domain); } - public void WriteS16(int addr, int value, string domain = null) + public void WriteS16(long addr, int value, string domain = null) { WriteSigned(addr, value, 2, domain); } - public uint ReadU16(int addr, string domain = null) + public uint ReadU16(long addr, string domain = null) { - return ReadUnsigned(addr, 2, domain); + return (ushort)ReadUnsigned(addr, 2, domain); } - public void WriteU16(int addr, uint value, string domain = null) + public void WriteU16(long addr, uint value, string domain = null) { WriteUnsigned(addr, value, 2, domain); } @@ -236,21 +239,21 @@ namespace BizHawk.Client.Common #region 3 Byte - public int ReadS24(int addr, string domain = null) + public int ReadS24(long addr, string domain = null) { return ReadSigned(addr, 3, domain); } - public void WriteS24(int addr, int value, string domain = null) + public void WriteS24(long addr, int value, string domain = null) { WriteSigned(addr, value, 3, domain); } - public uint ReadU24(int addr, string domain = null) + public uint ReadU24(long addr, string domain = null) { return ReadUnsigned(addr, 3, domain); } - public void WriteU24(int addr, uint value, string domain = null) + public void WriteU24(long addr, uint value, string domain = null) { WriteUnsigned(addr, value, 3, domain); } @@ -259,22 +262,22 @@ namespace BizHawk.Client.Common #region 4 Byte - public int ReadS32(int addr, string domain = null) + public int ReadS32(long addr, string domain = null) { return ReadSigned(addr, 4, domain); } - public void WriteS32(int addr, int value, string domain = null) + public void WriteS32(long addr, int value, string domain = null) { WriteSigned(addr, value, 4, domain); } - public uint ReadU32(int addr, string domain = null) + public uint ReadU32(long addr, string domain = null) { return ReadUnsigned(addr, 4, domain); } - public void WriteU32(int addr, uint value, string domain = null) + public void WriteU32(long addr, uint value, string domain = null) { WriteUnsigned(addr, value, 4, domain); } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs b/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs index 12dfc1ab3f..9816e9344d 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs @@ -5,12 +5,12 @@ using BizHawk.Emulation.Common.IEmulatorExtensions; namespace BizHawk.Client.Common { - public sealed class MemoryEventsPluginLibrary + public sealed class MemoryEventsPluginLibrary : PluginLibraryBase { [RequiredService] private IDebuggable DebuggableCore { get; set; } - public MemoryEventsPluginLibrary () + public MemoryEventsPluginLibrary () : base() { } public void AddReadCallback(Action cb, uint address, string domain) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs b/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs index f0916a518a..90950d6f73 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs @@ -6,10 +6,10 @@ using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public sealed class MemorySavestatePluginLibrary + public sealed class MemorySavestatePluginLibrary : PluginLibraryBase { - public MemorySavestatePluginLibrary() - { } + public MemorySavestatePluginLibrary() : base() + { } [RequiredService] private IStatable StatableCore { get; set; } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs index 6673f561ff..ac9552d9cd 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs @@ -4,9 +4,9 @@ using System.IO; namespace BizHawk.Client.Common { - public sealed class MoviePluginLibrary + public sealed class MoviePluginLibrary : PluginLibraryBase { - public MoviePluginLibrary() + public MoviePluginLibrary() : base() { } [LuaMethodExample("if ( movie.startsfromsavestate( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a savestate-anchored movie\" );\r\nend;")] diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs b/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs index 5271b82219..dae76333af 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs @@ -5,9 +5,9 @@ using System.Data.SQLite; namespace BizHawk.Client.Common { - public sealed class SQLPluginLibrary + public sealed class SQLPluginLibrary : PluginLibraryBase { - public SQLPluginLibrary() + public SQLPluginLibrary() : base() { } SQLiteConnection m_dbConnection; diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs index 3d60ad8fb1..27d2dc5af4 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs @@ -5,9 +5,9 @@ using BizHawk.Client.Common; namespace BizHawk.Client.Common { - public sealed class UserDataPluginLibrary + public sealed class UserDataPluginLibrary : PluginLibraryBase { - public UserDataPluginLibrary() + public UserDataPluginLibrary() : base() { } public void Set(string name, object value) diff --git a/BizHawk.Client.Common/plugins/PluginLibraryBase.cs b/BizHawk.Client.Common/plugins/PluginLibraryBase.cs index c480871c69..17485c7103 100644 --- a/BizHawk.Client.Common/plugins/PluginLibraryBase.cs +++ b/BizHawk.Client.Common/plugins/PluginLibraryBase.cs @@ -5,7 +5,6 @@ namespace BizHawk.Client.Common public abstract class PluginLibraryBase { protected PluginLibraryBase() { } - public abstract string Name { get; } protected static Color? ToColor(object o) { diff --git a/BizHawk.Client.Common/plugins/PluginMemoryBase.cs b/BizHawk.Client.Common/plugins/PluginMemoryBase.cs index 92bfad1a81..21bf8b89e0 100644 --- a/BizHawk.Client.Common/plugins/PluginMemoryBase.cs +++ b/BizHawk.Client.Common/plugins/PluginMemoryBase.cs @@ -8,7 +8,7 @@ namespace BizHawk.Client.Common /// /// Base class for the Memory and MainMemory plugin libraries /// - public abstract class PluginMemoryBase + public abstract class PluginMemoryBase : PluginLibraryBase { [RequiredService] protected IEmulator Emulator { get; set; } @@ -18,10 +18,8 @@ namespace BizHawk.Client.Common protected abstract MemoryDomain Domain { get; } - protected PluginMemoryBase() - { - - } + protected PluginMemoryBase() : base() + { } protected IMemoryDomains DomainList { @@ -58,7 +56,7 @@ namespace BizHawk.Client.Common return Domain.Name; } - protected uint ReadUnsignedByte(int addr, string domain = null) + protected uint ReadUnsignedByte(long addr, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; if (addr < d.Size) @@ -70,7 +68,7 @@ namespace BizHawk.Client.Common return 0; } - protected void WriteUnsignedByte(int addr, uint v, string domain = null) + protected void WriteUnsignedByte(long addr, uint v, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; if (d.CanPoke()) @@ -98,12 +96,12 @@ namespace BizHawk.Client.Common return s; } - protected int ReadSignedLittle(int addr, int size, string domain = null) + protected int ReadSignedLittle(long addr, int size, string domain = null) { return U2S(ReadUnsignedLittle(addr, size, domain), size); } - protected uint ReadUnsignedLittle(int addr, int size, string domain = null) + protected uint ReadUnsignedLittle(long addr, int size, string domain = null) { uint v = 0; for (var i = 0; i < size; ++i) @@ -114,12 +112,12 @@ namespace BizHawk.Client.Common return v; } - protected int ReadSignedBig(int addr, int size, string domain = null) + protected int ReadSignedBig(long addr, int size, string domain = null) { return U2S(ReadUnsignedBig(addr, size, domain), size); } - protected uint ReadUnsignedBig(int addr, int size, string domain = null) + protected uint ReadUnsignedBig(long addr, int size, string domain = null) { uint v = 0; for (var i = 0; i < size; ++i) @@ -130,12 +128,12 @@ namespace BizHawk.Client.Common return v; } - protected void WriteSignedLittle(int addr, int v, int size, string domain = null) + protected void WriteSignedLittle(long addr, int v, int size, string domain = null) { WriteUnsignedLittle(addr, (uint)v, size, domain); } - protected void WriteUnsignedLittle(int addr, uint v, int size, string domain = null) + protected void WriteUnsignedLittle(long addr, uint v, int size, string domain = null) { for (var i = 0; i < size; ++i) { @@ -143,12 +141,12 @@ namespace BizHawk.Client.Common } } - protected void WriteSignedBig(int addr, int v, int size, string domain = null) + protected void WriteSignedBig(long addr, int v, int size, string domain = null) { WriteUnsignedBig(addr, (uint)v, size, domain); } - protected void WriteUnsignedBig(int addr, uint v, int size, string domain = null) + protected void WriteUnsignedBig(long addr, uint v, int size, string domain = null) { for (var i = 0; i < size; ++i) { @@ -158,7 +156,7 @@ namespace BizHawk.Client.Common #region public Library implementations - protected List ReadByteRange(int addr, int length, string domain = null) + protected List ReadByteRange(long addr, int length, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; var lastAddr = length + addr; @@ -176,7 +174,7 @@ namespace BizHawk.Client.Common return list; } - protected void WriteByteRange(int addr, List memoryblock, string domain = null) + protected void WriteByteRange(long addr, List memoryblock, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; if (d.CanPoke()) @@ -199,7 +197,7 @@ namespace BizHawk.Client.Common } } - protected float ReadFloat(int addr, bool bigendian, string domain = null) + protected float ReadFloat(long addr, bool bigendian, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; if (addr < d.Size) @@ -214,7 +212,7 @@ namespace BizHawk.Client.Common return 0; } - protected void WriteFloat(int addr, double value, bool bigendian, string domain = null) + protected void WriteFloat(long addr, double value, bool bigendian, string domain = null) { var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; if (d.CanPoke()) diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs new file mode 100644 index 0000000000..b37d5f37dc --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs @@ -0,0 +1,351 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class EmuHawkPluginLibrary : PluginLibraryBase + { + [RequiredService] + private IEmulator Emulator { get; set; } + + [RequiredService] + private IVideoProvider VideoProvider { get; set; } + + private readonly Dictionary _filterMappings = new Dictionary + { + { 0, "None" }, + { 1, "x2SAI" }, + { 2, "SuperX2SAI" }, + { 3, "SuperEagle" }, + { 4, "Scanlines" }, + }; + + public EmuHawkPluginLibrary() : base() + { } + + public void CloseEmulator() + { + GlobalWin.MainForm.CloseEmulator(); + } + + public void CloseEmulatorWithCode(int exitCode) + { + GlobalWin.MainForm.CloseEmulator(exitCode); + } + + public static int BorderHeight() + { + var point = new System.Drawing.Point(0, 0); + return GlobalWin.DisplayManager.TransformPoint(point).Y; + } + + public static int BorderWidth() + { + var point = new System.Drawing.Point(0, 0); + return GlobalWin.DisplayManager.TransformPoint(point).X; + } + + public int BufferHeight() + { + return VideoProvider.BufferHeight; + } + + public int BufferWidth() + { + return VideoProvider.BufferWidth; + } + + public void ClearAutohold() + { + GlobalWin.MainForm.ClearHolds(); + } + + public static void CloseRom() + { + GlobalWin.MainForm.CloseRom(); + } + + public void EnableRewind(bool enabled) + { + GlobalWin.MainForm.EnableRewind(enabled); + } + + public void FrameSkip(int numFrames) + { + if (numFrames > 0) + { + Global.Config.FrameSkip = numFrames; + GlobalWin.MainForm.FrameSkipMessage(); + } + else + { + Console.WriteLine("Invalid frame skip value"); + } + } + + public static int GetTargetScanlineIntensity() + { + return Global.Config.TargetScanlineFilterIntensity; + } + + public int GetWindowSize() + { + return Global.Config.TargetZoomFactors[Emulator.SystemId]; + } + + public static void SetGameExtraPadding(int left, int top, int right, int bottom) + { + GlobalWin.DisplayManager.GameExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom); + GlobalWin.MainForm.FrameBufferResized(); + } + + public static void SetSoundOn(bool enable) + { + Global.Config.SoundEnabled = enable; + } + + public static bool GetSoundOn() + { + return Global.Config.SoundEnabled; + } + + public static void SetClientExtraPadding(int left, int top, int right, int bottom) + { + GlobalWin.DisplayManager.ClientExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom); + GlobalWin.MainForm.FrameBufferResized(); + } + + public static bool IsPaused() + { + return GlobalWin.MainForm.EmulatorPaused; + } + + public static bool IsTurbo() + { + return GlobalWin.MainForm.IsTurboing; + } + + public static bool IsSeeking() + { + return GlobalWin.MainForm.IsSeeking; + } + + public static void OpenCheats() + { + GlobalWin.Tools.Load(); + } + + public static void OpenHexEditor() + { + GlobalWin.Tools.Load(); + } + + public static void OpenRamWatch() + { + GlobalWin.Tools.LoadRamWatch(loadDialog: true); + } + + public static void OpenRamSearch() + { + GlobalWin.Tools.Load(); + } + + public static void OpenRom(string path) + { + var ioa = OpenAdvancedSerializer.ParseWithLegacy(path); + GlobalWin.MainForm.LoadRom(path, new MainForm.LoadRomArgs { OpenAdvanced = ioa }); + } + + public static void OpenTasStudio() + { + GlobalWin.Tools.Load(); + } + + public static void OpenToolBox() + { + GlobalWin.Tools.Load(); + } + + public static void OpenTraceLogger() + { + GlobalWin.Tools.Load(); + } + + public static void Pause() + { + GlobalWin.MainForm.PauseEmulator(); + } + + public static void PauseAv() + { + GlobalWin.MainForm.PauseAvi = true; + } + + public static void RebootCore() + { + ((LuaConsole)GlobalWin.Tools.Get()).LuaImp.IsRebootingCore = true; + GlobalWin.MainForm.RebootCore(); + ((LuaConsole)GlobalWin.Tools.Get()).LuaImp.IsRebootingCore = false; + } + + public static int ScreenHeight() + { + return GlobalWin.MainForm.PresentationPanel.NativeSize.Height; + } + + public static void Screenshot(string path = null) + { + if (path == null) + { + GlobalWin.MainForm.TakeScreenshot(); + } + else + { + GlobalWin.MainForm.TakeScreenshot(path); + } + } + + public static void ScreenshotToClipboard() + { + GlobalWin.MainForm.TakeScreenshotToClipboard(); + } + + public static void SetTargetScanlineIntensity(int val) + { + Global.Config.TargetScanlineFilterIntensity = val; + } + + public static void SetScreenshotOSD(bool value) + { + Global.Config.Screenshot_CaptureOSD = value; + } + + public static int ScreenWidth() + { + return GlobalWin.MainForm.PresentationPanel.NativeSize.Width; + } + + public void SetWindowSize(int size) + { + if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10) + { + Global.Config.TargetZoomFactors[Emulator.SystemId] = size; + GlobalWin.MainForm.FrameBufferResized(); + GlobalWin.OSD.AddMessage("Window size set to " + size + "x"); + } + else + { + Console.WriteLine("Invalid window size"); + } + } + + public void SpeedMode(int percent) + { + if (percent > 0 && percent < 6400) + { + GlobalWin.MainForm.ClickSpeedItem(percent); + } + else + { + Console.WriteLine("Invalid speed value"); + } + } + + public static void TogglePause() + { + GlobalWin.MainForm.TogglePause(); + } + + public static int TransformPointX(int x) + { + var point = new System.Drawing.Point(x, 0); + return GlobalWin.DisplayManager.TransformPoint(point).X; + } + + public static int TransformPointY(int y) + { + var point = new System.Drawing.Point(0, y); + return GlobalWin.DisplayManager.TransformPoint(point).Y; + } + + public static void Unpause() + { + GlobalWin.MainForm.UnpauseEmulator(); + } + + public static void UnpauseAv() + { + GlobalWin.MainForm.PauseAvi = false; + } + + public static int Xpos() + { + return GlobalWin.MainForm.DesktopLocation.X; + } + + public static int Ypos() + { + return GlobalWin.MainForm.DesktopLocation.Y; + } + + public List GetAvailableTools() + { + var tools = GlobalWin.Tools.AvailableTools.ToList(); + var t = new List(tools.Count); + for (int i = 0; i < tools.Count; i++) + { + t[i] = tools[i].Name.ToLower(); + } + + return t; + } + + public Type GetTool(string name) + { + var toolType = ReflectionUtil.GetTypeByName(name) + .FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface); + + if (toolType != null) + { + GlobalWin.Tools.Load(toolType); + } + + var selectedTool = GlobalWin.Tools.AvailableTools + .FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower()); + + if (selectedTool != null) + { + return selectedTool; + } + + return null; + } + + public object CreateInstance(string name) + { + var possibleTypes = ReflectionUtil.GetTypeByName(name); + + if (possibleTypes.Any()) + { + return Activator.CreateInstance(possibleTypes.First()); + } + + return null; + } + + public void DisplayMessages(bool value) + { + Global.Config.DisplayMessages = value; + } + + public void SaveRam() + { + GlobalWin.MainForm.FlushSaveRAM(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs new file mode 100644 index 0000000000..43012c1817 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs @@ -0,0 +1,121 @@ +using System; +using System.ComponentModel; + +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; +using System.Text; +using System.Collections.Generic; +using System.Net.Http; +using System.Windows.Forms; + + +namespace BizHawk.Client.EmuHawk +{ + public sealed class CommunicationPluginLibrary : PluginLibraryBase + { + [RequiredService] + private IEmulator Emulator { get; set; } + + [RequiredService] + private IVideoProvider VideoProvider { get; set; } + + public CommunicationPluginLibrary() : base() + { } + + public string SocketServerScreenShot() + { + return GlobalWin.socketServer.SendScreenshot(); + } + public string SocketServerScreenShotResponse() + { + return GlobalWin.socketServer.SendScreenshot(1000).ToString(); + } + + public string SocketServerSend(string SendString) + { + return "Sent : " + GlobalWin.socketServer.SendString(SendString).ToString() + " bytes"; + } + public string SocketServerResponse() + { + return GlobalWin.socketServer.ReceiveMessage(); + } + + public bool SocketServerSuccessful() + { + return GlobalWin.socketServer.Successful(); + } + public void SocketServerSetTimeout(int timeout) + { + GlobalWin.socketServer.SetTimeout(timeout); + } + // All MemoryMappedFile related methods + public void MmfSetFilename(string filename) + { + GlobalWin.memoryMappedFiles.SetFilename(filename); + } + public string MmfSetFilename() + { + return GlobalWin.memoryMappedFiles.GetFilename(); + } + + public int MmfScreenshot() + { + return GlobalWin.memoryMappedFiles.ScreenShotToFile(); + } + + public int MmfWrite(string mmf_filename, string outputString) + { + return GlobalWin.memoryMappedFiles.WriteToFile(mmf_filename, Encoding.ASCII.GetBytes(outputString)); + } + public string MmfRead(string mmf_filename, int expectedSize) + { + return GlobalWin.memoryMappedFiles.ReadFromFile(mmf_filename, expectedSize).ToString(); + } + // All HTTP related methods + public string HttpTest() + { + var list = new StringBuilder(); + list.AppendLine(GlobalWin.httpCommunication.TestGet()); + list.AppendLine(GlobalWin.httpCommunication.SendScreenshot()); + list.AppendLine("done testing"); + return list.ToString(); + } + public string HttpTestGet() + { + return GlobalWin.httpCommunication.TestGet(); + } + public string HttpGet(string url) + { + return GlobalWin.httpCommunication.ExecGet(url); + } + + public string HttpPost(string url, string payload) + { + return GlobalWin.httpCommunication.ExecPost(url, payload); + } + public string HttpPostScreenshot() + { + return GlobalWin.httpCommunication.SendScreenshot(); + } + public void HttpSetTimeout(int timeout) + { + GlobalWin.httpCommunication.SetTimeout(timeout); + } + public void HttpSetPostUrl(string url) + { + GlobalWin.httpCommunication.SetPostUrl(url); + } + public void HttpSetGetUrl(string url) + { + GlobalWin.httpCommunication.SetGetUrl(url); + } + public string HttpGetPostUrl() + { + return GlobalWin.httpCommunication.GetPostUrl(); + } + public string HttpGetGetUrl() + { + return GlobalWin.httpCommunication.GetGetUrl(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs similarity index 95% rename from BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs rename to BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs index 90b6ddba27..e22bd3e0fd 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/Plugin.GUILibrary.cs +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs @@ -5,11 +5,10 @@ using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public sealed class GUIPluginLibrary : GUIDrawPluginLibrary + public sealed class GUIPluginLibrary : GUIDrawPluginBase { - public GUIPluginLibrary() - { - } + public GUIPluginLibrary() : base() + { } private DisplaySurface _GUISurface = null; @@ -114,7 +113,7 @@ namespace BizHawk.Client.EmuHawk var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel); Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize(); var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0)); - g.FillRectangle(GetBrush(backcolor ?? _defaultTextBackground.Value), rect); + if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y); } diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs new file mode 100644 index 0000000000..e2e289bae0 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Windows.Forms; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class InputPluginLibrary : PluginLibraryBase + { + public InputPluginLibrary() : base() + { } + + public Dictionary Get() + { + var buttons = new Dictionary(); + foreach (var kvp in Global.ControllerInputCoalescer.BoolButtons().Where(kvp => kvp.Value)) + { + buttons[kvp.Key] = true; + } + + return buttons; + } + + public Dictionary GetMouse() + { + var buttons = new Dictionary(); + + // TODO - need to specify whether in "emu" or "native" coordinate space. + var p = GlobalWin.DisplayManager.UntransformPoint(Control.MousePosition); + buttons["X"] = p.X; + buttons["Y"] = p.Y; + buttons[MouseButtons.Left.ToString()] = (Control.MouseButtons & MouseButtons.Left) != 0; + buttons[MouseButtons.Middle.ToString()] = (Control.MouseButtons & MouseButtons.Middle) != 0; + buttons[MouseButtons.Right.ToString()] = (Control.MouseButtons & MouseButtons.Right) != 0; + buttons[MouseButtons.XButton1.ToString()] = (Control.MouseButtons & MouseButtons.XButton1) != 0; + buttons[MouseButtons.XButton2.ToString()] = (Control.MouseButtons & MouseButtons.XButton2) != 0; + buttons["Wheel"] = GlobalWin.MainForm.MouseWheelTracker; + return buttons; + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs new file mode 100644 index 0000000000..90f4e5e7f6 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class SavestatePluginibrary : PluginLibraryBase + { + public SavestatePluginibrary() : base() + { } + + public void Load(string path) + { + if (!File.Exists(path)) + { + Console.WriteLine($"could not find file: {path}"); + } + else + { + GlobalWin.MainForm.LoadState(path, Path.GetFileName(path), true); + } + } + + public void LoadSlot(int slotNum) + { + if (slotNum >= 0 && slotNum <= 9) + { + GlobalWin.MainForm.LoadQuickSave("QuickSave" + slotNum, true); + } + } + + public void Save(string path) + { + GlobalWin.MainForm.SaveState(path, path, true); + } + + public void SaveSlot(int slotNum) + { + if (slotNum >= 0 && slotNum <= 9) + { + GlobalWin.MainForm.SaveQuickSave("QuickSave" + slotNum); + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs new file mode 100644 index 0000000000..1396c77334 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk + +{ + public class PluginLibrary + { +// public LuaDocumentation Docs { get; } + public PluginLibrary(IEmulatorServiceProvider serviceProvider) + { + // Docs.Clear(); + + // Register lua libraries + var libs = Assembly + .Load("BizHawk.Client.Common") + .GetTypes() + .Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) + .ToList(); + + libs.AddRange( + Assembly + .GetAssembly(typeof(PluginLibrary)) + .GetTypes() + .Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); + + foreach (var lib in libs) + { + bool addLibrary = true; + //var attributes = lib.GetCustomAttributes(typeof(LuaLibraryAttribute), false); + //if (attributes.Any()) + //{ + // addLibrary = VersionInfo.DeveloperBuild || (attributes.First() as LuaLibraryAttribute).Released; + //} + + if (addLibrary) + { + var instance = (PluginLibraryBase)Activator.CreateInstance(lib); + //instance.LuaRegister(lib, Docs); + //instance.LogOutputCallback = ConsoleLuaLibrary.LogOutput; + ServiceInjector.UpdateServices(serviceProvider, instance); + Libraries.Add(lib, instance); + } + } + } + private readonly Dictionary Libraries = new Dictionary(); + public List PluginList { get; } = new List(); + + public IEnumerable RunningPlugins + { + get { return PluginList.Where(plug => plug.Enabled); } + } + +// private FormsPluginLibrary FormsLibrary => (FormsLuaLibrary)Libraries[typeof(FormsLuaLibrary)]; + private EmulatorPluginLibrary EmulatorLuaLibrary => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)]; + public GUIPluginLibrary GuiLibrary => (GUIPluginLibrary)Libraries[typeof(GUIPluginLibrary)]; + + public void Restart(IEmulatorServiceProvider newServiceProvider) + { + foreach (var lib in Libraries) + { + ServiceInjector.UpdateServices(newServiceProvider, lib.Value); + } + foreach (var plugin in PluginList) + { + plugin.Init(new PluginAPI(Libraries)); + } + } + + public void StartPluginDrawing() + { + if (PluginList.Any() && !GuiLibrary.HasGUISurface) + { + GuiLibrary.DrawNew("emu"); + } + } + + public void EndPluginDrawing() + { + if (PluginList.Any()) + { + GuiLibrary.DrawFinish(); + } + } + + public void CallSaveStateEvent(string name) + { + foreach (var plugin in RunningPlugins) plugin.SaveStateCallback(name); + } + + public void CallLoadStateEvent(string name) + { + foreach (var plugin in RunningPlugins) plugin.LoadStateCallback(name); + } + + public void CallFrameBeforeEvent() + { + StartPluginDrawing(); + foreach (var plugin in RunningPlugins) plugin.PreFrameCallback(); + } + + public void CallFrameAfterEvent() + { + foreach (var plugin in RunningPlugins) plugin.PostFrameCallback(); + EndPluginDrawing(); + } + + public void CallExitEvent() + { + foreach (var plugin in RunningPlugins) plugin.ExitCallback(); + } + + public void Close() + { + GuiLibrary.Dispose(); + } + + public void Load(PluginBase plugin) + { + plugin.Init(new PluginAPI(Libraries)); + PluginList.Add(plugin); + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs b/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs new file mode 100644 index 0000000000..c2e1ea3960 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class PluginAPI : IPluginAPI + { + public EmulatorPluginLibrary EmuLib => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)]; + public GameInfoPluginLibrary GameInfoLib => (GameInfoPluginLibrary)Libraries[typeof(GameInfoPluginLibrary)]; + public GUIDrawPluginBase GUILib => (GUIDrawPluginBase)Libraries[typeof(GUIPluginLibrary)]; + public JoypadPluginLibrary JoypadLib => (JoypadPluginLibrary)Libraries[typeof(JoypadPluginLibrary)]; + public MemoryPluginLibrary MemLib => (MemoryPluginLibrary)Libraries[typeof(MemoryPluginLibrary)]; + public MemoryEventsPluginLibrary MemEventsLib => (MemoryEventsPluginLibrary)Libraries[typeof(MemoryEventsPluginLibrary)]; + public MemorySavestatePluginLibrary MemStateLib => (MemorySavestatePluginLibrary)Libraries[typeof(MemorySavestatePluginLibrary)]; + public MoviePluginLibrary MovieLib => (MoviePluginLibrary)Libraries[typeof(MoviePluginLibrary)]; + public SQLPluginLibrary SQLLib => (SQLPluginLibrary)Libraries[typeof(SQLPluginLibrary)]; + public UserDataPluginLibrary UserDataLib => (UserDataPluginLibrary)Libraries[typeof(UserDataPluginLibrary)]; + public Dictionary Libraries { get; set; } + public PluginAPI(Dictionary libs) + { + Libraries = libs; + } + } +} From 6eed08f9653a36a3e87d28d0dbfc3e8b1a9b4b87 Mon Sep 17 00:00:00 2001 From: upthorn Date: Mon, 3 Sep 2018 19:31:43 -0700 Subject: [PATCH 005/440] An example plugin. Hard-coded for now. --- .../BizHawk.Client.EmuHawk.csproj | 9 +- BizHawk.Client.EmuHawk/GlobalWin.cs | 1 + BizHawk.Client.EmuHawk/MainForm.cs | 8 + .../Plugins/Example/Ecco2AssistantPlugin.cs | 798 ++++++++++++++++++ 4 files changed, 815 insertions(+), 1 deletion(-) create mode 100644 BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index e4d50eb1de..3b5cf29d1d 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -634,7 +634,9 @@ - + + + @@ -719,6 +721,10 @@ PlatformChooser.cs + + + + @@ -1841,6 +1847,7 @@ + diff --git a/BizHawk.Client.EmuHawk/GlobalWin.cs b/BizHawk.Client.EmuHawk/GlobalWin.cs index 5df3f651bf..5ede6c61fc 100644 --- a/BizHawk.Client.EmuHawk/GlobalWin.cs +++ b/BizHawk.Client.EmuHawk/GlobalWin.cs @@ -7,6 +7,7 @@ namespace BizHawk.Client.EmuHawk { public static MainForm MainForm; public static ToolManager Tools; + public static PluginLibrary Plugins; /// /// the IGL to be used for rendering diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index a989739283..9e488a00d5 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -253,6 +253,8 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Sound.StartSound(); InputManager.RewireInputChain(); GlobalWin.Tools = new ToolManager(this); + GlobalWin.Plugins = new PluginLibrary(Emulator.ServiceProvider); + GlobalWin.Plugins.Load(new Ecco2AssistantPlugin()); RewireSound(); // Workaround for windows, location is -32000 when minimized, if they close it during this time, that's what gets saved @@ -2925,6 +2927,7 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallFrameBeforeEvent(); } + GlobalWin.Plugins.CallFrameBeforeEvent(); if (IsTurboing) { @@ -3011,6 +3014,7 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallFrameAfterEvent(); } + GlobalWin.Plugins.CallFrameAfterEvent(); if (IsTurboing) { @@ -3744,6 +3748,7 @@ namespace BizHawk.Client.EmuHawk } GlobalWin.Tools.Restart(); + GlobalWin.Plugins.Restart(Emulator.ServiceProvider); if (Global.Config.LoadCheatFileByGame) { @@ -3917,6 +3922,7 @@ namespace BizHawk.Client.EmuHawk Global.Game = GameInfo.NullInstance; GlobalWin.Tools.Restart(); + GlobalWin.Plugins.Restart(Emulator.ServiceProvider); RewireSound(); Text = "BizHawk" + (VersionInfo.DeveloperBuild ? " (interim) " : ""); HandlePlatformMenus(); @@ -4012,6 +4018,7 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallLoadStateEvent(userFriendlyStateName); } + GlobalWin.Plugins.CallLoadStateEvent(userFriendlyStateName); SetMainformMovieInfo(); GlobalWin.Tools.UpdateToolsBefore(fromLua); @@ -4141,6 +4148,7 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallSaveStateEvent(quickSlotName); } + GlobalWin.Plugins.CallSaveStateEvent(quickSlotName); } private void SaveStateAs() diff --git a/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs b/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs new file mode 100644 index 0000000000..753bc5d425 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs @@ -0,0 +1,798 @@ +using System; +using System.Collections.Generic; +using System.Drawing; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class Ecco2AssistantPlugin : PluginBase + { + public override string Name => "Ecco 2 Assistant"; + + public override string Description => "Displays a hud with hitboxes, etc. Assists with maintaining maximum speed."; + + private enum Modes { disabled, Ecco1, Ecco2 } + private Modes _mode; + + private int _camX = 0; + private int _camY = 0; + private int _camXAddr; + private int _camYAddr; + private bool _prevOn = false; + private uint _prevCharge = 0; + private uint _prevF = 0; + + void DrawEccoOct(int x, int y, int r, Color? color = null, int fillAlpha = 0) + { + Point[] octPoints = { + new Point(x, y - r), + new Point((int)(x + Math.Sin(Math.PI / 4) * r), (int)(y - Math.Sin(Math.PI / 4) *r)), + new Point(x + r, y), + new Point((int)(x + Math.Sin(Math.PI / 4) * r), (int)(y + Math.Sin(Math.PI / 4) *r)), + new Point(x, y + r), + new Point((int)(x - Math.Sin(Math.PI / 4) * r), (int)(y + Math.Sin(Math.PI / 4) *r)), + new Point(x - r, y), + new Point((int)(x - Math.Sin(Math.PI / 4) * r), (int)(y - Math.Sin(Math.PI / 4) *r)) + }; + Color fillColor = color.HasValue ? Color.FromArgb(fillAlpha, color.Value) : Color.Empty; + _api.GUILib.DrawPolygon(octPoints, color, fillColor); + } + void DrawBoxMWH(int x, int y, int w, int h, Color? color = null, int fillAlpha = 0) + { + Color fillColor = color.HasValue ? Color.FromArgb(fillAlpha, color.Value) : Color.Empty; + _api.GUILib.DrawRectangle(x - w, y - h, w << 1, h << 1, color, fillColor); + } + void Print_Text(string message, int size, int x, int y, Color color) + { + _api.GUILib.DrawText(x, y, message, color, null); + } + void PutText(string message, int x, int y, int xl, int yl, int xh, int yh, Color bg, Color fg) + { + xl = Math.Max(xl, 0); + yl = Math.Max(xl, 0); + xh = Math.Min(xh + 639, 639); + yh = Math.Min(yh + 441, 441); + xh -= 4 * message.Length; + x = x - ((5 * (message.Length - 1)) / 2); + x = Math.Min(Math.Max(x, Math.Max(xl, 1)), Math.Min(xh, 638 - 4 * (int)message.Length)); + y = Math.Min(Math.Max(y - 3, Math.Max(yl, 1)), yh); + int[] xOffset = { -1, -1, -1, 0, 1, 1, 1, 0 }; + int[] yOffset = { -1, 0, 1, 1, 1, 0, -1, -1 }; + for (int i = 0; i < 8; i++) + Print_Text(message, message.Length, x + xOffset[i], y + yOffset[i], bg); + Print_Text(message, message.Length, x, y, fg); + } + + + void EccoDraw3D() + { + int ScreenX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC); + int ScreenY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC); + int ScreenZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xB); + uint curObj = _api.MemLib.ReadU24(0xFFD4C1); + while (curObj != 0) + { + int Xpos = (_api.MemLib.ReadS32(curObj + 0x6) >> 0xC); + int Ypos = (_api.MemLib.ReadS32(curObj + 0xE) >> 0xC); + int Zpos = (_api.MemLib.ReadS32(curObj + 0xA) >> 0xB); + int Y = 224 - (Zpos - ScreenZ); + int X = (Xpos - ScreenX) + 0xA0; + uint type = _api.MemLib.ReadU32(curObj + 0x5A); + short height, width; + int display = 0; + if ((type == 0xD817E) || (type == 0xD4AB8)) + { + Y = 113 - (Ypos - ScreenY); + height = 0x10; + if (_api.MemLib.ReadU32(0xFFB166) < 0x1800) height = 0x8; + short radius = 31; + if (type == 0xD4AB8) + { + radius = 7; + height = 0x20; + } + width = radius; + DrawEccoOct(X, Y, radius, Color.Lime, 0); + display = 1; + } + else + { + width = height = 1; + if (curObj == 0xFFB134) display = 3; + } + if ((display & 1) != 0) + { + Y = 224 - (Zpos - ScreenZ); + DrawBoxMWH(X, Y, width, height, Color.Blue, 0); + } + if ((display & 2) != 0) + { + Y = 113 - (Ypos - ScreenY); + DrawBoxMWH(X, Y, width, height, Color.Lime, 0); + } + curObj = _api.MemLib.ReadU24(curObj+1); + } + } + void EccoDrawBoxes() + { + // CamX-=8; + int Width2, Height2; + //Ecco HP and Air + int i = 0; + int HP = _api.MemLib.ReadS16(0xFFAA16) << 3; + int air = _api.MemLib.ReadS16(0xFFAA18); + Color color; + int off = 0; + for (int j = 0; j < air; j++) + { + if (j - off == 448) + { + i++; off += 448; + } + color = Color.FromArgb(j >> 2, j >> 2, j >> 2); + _api.GUILib.DrawLine(128, j - off, 144, j - off, color); + } + for (i = 0; i < 16; i++) + for (int j = 0; j < Math.Min(HP, 448); j++) + { + color = Color.FromArgb(0, 0, (j>>1 & 0xF0)); + _api.GUILib.DrawPixel(144 + i, j, color); + } + + //Asterite + uint curObj = _api.MemLib.ReadU24(0xFFCFC9); + int Xpos, Xpos2, Ypos, Ypos2, Xmid, Ymid, X, X2, Y, Y2; + Xmid = 0; + Ymid = 0; + while (curObj != 0) + { + if (_api.MemLib.ReadU32(curObj + 8) != 0) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x3C); + Xpos2= _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x40); + Ypos2= _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + if (_api.MemLib.ReadU8(curObj + 0x71) != 0) + { + DrawEccoOct(Xpos, Ypos, 40, Color.FromArgb(255, 192, 0), 0x7F); + DrawEccoOct(Xpos2, Ypos2, 40, Color.FromArgb(255, 192, 0), 0x7F); + } + } + else + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + } + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(0, Ymid-5), 424), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(2, Ymid-3), 426), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(2, Ymid-3), 426), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(0, Ymid-5), 424), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(1, Xmid-15), 606), Math.Min(Math.Max(1, Ymid-4), 425), Color.Blue); + curObj = _api.MemLib.ReadU24(curObj+1); + } + uint curlev = _api.MemLib.ReadU8(0xFFA7E0); + if ((_api.MemLib.ReadU8(0xFFA7D0) == 30)) + { + curObj = _api.MemLib.ReadU24(0xFFD425); + if ((curObj != 0) && (_api.MemLib.ReadU32(curObj + 8) != 0)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawEccoOct(Xpos, Ypos, 20, Color.FromArgb(255, 192, 0)); + } + } + //aqua tubes + curObj = _api.MemLib.ReadU24(0xFFCFC5); + while (curObj != 0) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2= _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + // displayed = false; + uint type = _api.MemLib.ReadU8(curObj + 0x7E); + int yoff = 0; + switch (type) + { + /* case 0x11: + Xpos2 = Xmid; + Xmid = (Xpos + Xpos2) >> 1; + break; + case 0x12: + Xpos = Xmid; + Xmid = (Xpos + Xpos2) >> 1; + break; + case 0x13: + Ypos = Ymid; + Ymid = (Ypos + Ypos2) >> 1; + break; + case 0x14: + Ypos2 = Ymid; + Ymid = (Ypos + Ypos2) >> 1; + break;*/ + case 0x15: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) + _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid + yoff, Color.FromArgb(127, 0, 255)); + for (int TempX = Math.Min(Math.Max(0, Xmid), 320); TempX <= Math.Min(Math.Max(8, Xpos2), 327); TempX++) + _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); + for (uint TempX = (uint)Math.Min(Math.Max(0, Ymid), 223); TempX <= Math.Min(Math.Max(0, Ypos2), 223); TempX++) + _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); + break; + case 0x18: + case 0x19: + for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xmid + yoff, Ypos2-TempX, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x1A: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) + _api.GUILib.DrawPixel(Xpos + TempX, Ymid + yoff, Color.FromArgb(127, 0, 255)); + for (int TempX = Math.Min(Math.Max(0, Xpos), 320); TempX <= Math.Min(Math.Max(8, Xmid), 327); TempX++) + _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); + for (uint TempX = (uint)Math.Min(Math.Max(0, Ymid), 223); TempX <= Math.Min(Math.Max(0, Ypos2), 223); TempX++) + _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); + break; + case 0x1D: + for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xmid - yoff, Ypos2 - TempX, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x1F: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) + _api.GUILib.DrawPixel(Xpos + TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); + for (int TempX = Math.Min(Math.Max(0, Xpos), 320); TempX <= Math.Min(Math.Max(8, Xmid), 327); TempX++) + _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); + for (uint TempX = (uint)Math.Min(Math.Max(0, Ypos), 223); TempX <= Math.Min(Math.Max(0, Ymid), 223); TempX++) + _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); + break; + case 0x20: + case 0x21: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++) + { + _api.GUILib.DrawPixel(Xpos + TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x22: + case 0x23: + for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xmid - yoff, Ypos + TempX, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x24: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) + _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); + break; + case 0x25: + case 0x26: + for (int TempX = 0; TempX <= Xmid-Xpos; TempX++) + { + _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x27: + case 0x28: + for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xmid + yoff, Ypos + TempX, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + break; + case 0x2B: + _api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.FromArgb(127, 0, 255)); + for (int TempX = 0; TempX <= Ymid - Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xpos + yoff, Ymid - TempX, Color.FromArgb(127, 0, 255)); + _api.GUILib.DrawPixel(Xpos2 - yoff, Ymid - TempX, Color.FromArgb(127, 0, 255)); + if ((TempX & 1) != 0) yoff++; + } + yoff = Xmid - (Xpos + yoff); + _api.GUILib.DrawLine(Xmid - yoff, Ypos, Xmid + yoff, Ypos, Color.FromArgb(127, 0, 255)); + break; + default: + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(255, 127, 0, 255)); + break; + } + // if (!displayed) + if (type != 0x10) + { + uint temp = _api.MemLib.ReadU8(curObj + 0x7E); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(1, Xmid-2), 629), Math.Min(Math.Max(1, Ymid-4), 425), Color.Blue); + } + curObj = _api.MemLib.ReadU24(curObj+1); + } + //walls + bool displayed; + curObj = _api.MemLib.ReadU24(0xFFCFC1); + while (curObj != 0) + { + + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2= _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + displayed = false; + uint type = _api.MemLib.ReadU8(curObj + 0x7E); + int yoff = 0; + switch (type) + { + case 0x11: + Xpos2 = Xmid; + Xmid = (Xpos + Xpos2) >> 1; + break; + case 0x12: + Xpos = Xmid; + Xmid = (Xpos + Xpos2) >> 1; + break; + case 0x13: + Ypos = Ymid; + Ymid = (Ypos + Ypos2) >> 1; + break; + case 0x14: + Ypos2 = Ymid; + Ymid = (Ypos + Ypos2) >> 1; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.White); + _api.GUILib.DrawLine(Xmid, Ypos2, Xmid, Ymid, Color.FromArgb(127,Color.White)); + _api.GUILib.DrawLine(Xmid, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); + displayed = true; + break; + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.White); + _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ypos2, Color.FromArgb(127, Color.White)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ymid, Color.FromArgb(127, Color.White)); + displayed = true; + break; + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.White); + _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ypos, Color.FromArgb(127, Color.White)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ymid, Color.FromArgb(127, Color.White)); + displayed = true; + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.White); + _api.GUILib.DrawLine(Xmid, Ypos, Xmid, Ymid, Color.FromArgb(127, Color.White)); + _api.GUILib.DrawLine(Xmid, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); + displayed = true; + break; + case 0x2B: + _api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); + for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + { + _api.GUILib.DrawPixel(Xpos + yoff, Ymid - TempX, Color.White); + _api.GUILib.DrawPixel(Xpos2 - yoff, Ymid - TempX, Color.White); + if ((TempX & 1) != 0) yoff++; + } + yoff = Xmid - (Xpos + yoff); + _api.GUILib.DrawLine(Xmid - yoff, Ypos, Xmid + yoff, Ypos); + displayed = true; + break; + default: + if (type != 0x10) + { + var temp = _api.MemLib.ReadU8(curObj + 0x7E); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); + Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(1, Xmid-2), 629), Math.Min(Math.Max(1, Ymid-4), 425), Color.Lime); + } + break; + } + if (!displayed) _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); + curObj = _api.MemLib.ReadU24(curObj+1); + } + //inanimate objects + curObj = _api.MemLib.ReadU24(0xFFCFBD); + while (curObj != 0) + { + if (_api.MemLib.ReadU8(curObj + 0x7E) > 0xF); + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2= _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + } + Xpos += Xpos2; + Ypos += Ypos2; + Xpos >>= 1; + Ypos >>= 1; + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xpos-16), 605), Math.Min(Math.Max(0, Ypos-5), 424), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xpos-14), 607), Math.Min(Math.Max(2, Ypos-3), 426), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xpos-16), 605), Math.Min(Math.Max(2, Ypos-3), 426), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xpos-14), 607), Math.Min(Math.Max(0, Ypos-5), 424), Color.Lime); + Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(1, Xpos-15), 606), Math.Min(Math.Max(1, Ypos-4), 425), Color.Blue); + curObj = _api.MemLib.ReadU24(curObj+1); + } + //animate objects + if (_mode == Modes.Ecco2) + curObj = _api.MemLib.ReadU24(0xFFCFB9); + else + curObj = _api.MemLib.ReadU24(0xFFD829); + while (curObj != 0) + { + uint type = 0; + switch (_mode) { + case Modes.Ecco2: + { + uint flags = _api.MemLib.ReadU16(curObj + 0x10); + //if ((flags & 0x2000) || !(flags & 2)); + type = _api.MemLib.ReadU32(curObj + 0xC); + if ((type == 0xBA52E) || (type == 0xBA66E)) + { + uint Adelikat = curObj; + while (Adelikat != 0) + { + Xpos = _api.MemLib.ReadS16(Adelikat + 0x24); + Ypos = _api.MemLib.ReadS16(Adelikat + 0x28); + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(Adelikat + 0x44), Color.Lime); + Adelikat = _api.MemLib.ReadU32(Adelikat + 4); + } + Xpos = _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; + Ypos -= _camY; + } + else if (type == 0xE47EE) + { + uint Adelikat = curObj; + while (Adelikat != 0) + { + Xpos = _api.MemLib.ReadS16(Adelikat + 0x1C); + Ypos = _api.MemLib.ReadS16(Adelikat + 0x20); + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, (_api.MemLib.ReadS16(Adelikat + 0x2C) >> 1) + 16, Color.Lime); + Adelikat = _api.MemLib.ReadU32(Adelikat + 4); + } + Xpos = _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; + Ypos -= _camY; + } + else if ((type == 0x9F5B0) || (type == 0xA3B18)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Lime); + } + else if (type == 0xDCEE0) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, 0x5C, Color.Lime); + } + else + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS16(curObj + 0x24); + Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + if ((type == 0xA6C4A) || (type == 0xC43D4)) DrawEccoOct(Xmid, Ymid, 70, Color.Lime); + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + } + break; + } + case Modes.Ecco1: + type = _api.MemLib.ReadU32(curObj + 0x6); + Xpos = _api.MemLib.ReadS16(curObj + 0x17); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x1F); + Ypos = _api.MemLib.ReadS16(curObj + 0x1B); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x23); + Xmid = _api.MemLib.ReadS16(curObj + 0x0F); + Ymid = _api.MemLib.ReadS16(curObj + 0x13); + Xpos >>= 2; + Xpos2 >>= 2; + Ypos >>= 2; + Ypos2 >>= 2; + Xmid >>= 2; + Ymid >>= 2; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + break; + } + Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(0, Ymid-5), 424), Color.Blue); + Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(2, Ymid-3), 426), Color.Blue); + Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(2, Ymid-3), 426), Color.Blue); + Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(0, Ymid-5), 424), Color.Blue); + Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(1, Xmid-15), 606), Math.Min(Math.Max(1, Ymid-4), 425), Color.Red); + curObj = _api.MemLib.ReadU24(curObj+1); + } + //events + curObj = _api.MemLib.ReadU24(0xFFCFB5); + while (curObj != 0) + { + uint type = _api.MemLib.ReadU32(curObj + 0xC); + if ((type == 0xA44EE) || (type == 0xD120C)) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawEccoOct(Xmid, Ymid, 0x20, Color.Cyan); + } + else if (type == 0xDEF94) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawEccoOct(Xmid, Ymid, 0x18, Color.Cyan); + } + else + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2= _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS16(curObj + 0x24); + Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); + } + PutText(type.ToString("X8"), Xmid, Ymid, 1, 1, 0, 0, Color.White, Color.Blue); + PutText(curObj.ToString("X8"), Xmid, Ymid, 1, 9, 0, 0, Color.White, Color.Blue); + curObj = _api.MemLib.ReadU24(curObj+1); + } + //Ecco body + Xpos = _api.MemLib.ReadS16(0xFFAA22); + Ypos = _api.MemLib.ReadS16(0xFFAA26); + Xpos2 = _api.MemLib.ReadS16(0xFFAA2A); + Ypos2 = _api.MemLib.ReadS16(0xFFAA2E); + Xmid = _api.MemLib.ReadS16(0xFFAA1A); + Ymid = _api.MemLib.ReadS16(0xFFAA1E); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + X = Xpos; + X2 = Xpos2; + Y = Ypos; + Y2 = Ypos2; + int X3 = (Xmid + (ushort) Xpos) >> 1; + int X4 = (Xmid + (ushort) Xpos2) >> 1; + int Y3 = (Ymid + (ushort) Ypos) >> 1; + int Y4 = (Ymid + (ushort) Ypos2) >> 1; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Magenta); + DrawBoxMWH(X, Y, 1, 1, Color.Magenta); + DrawBoxMWH(X2, Y2, 1, 1, Color.Magenta); + DrawBoxMWH(X3, Y3, 1, 1, Color.Magenta); + DrawBoxMWH(X4, Y4, 1, 1, Color.Magenta); + _api.GUILib.DrawPixel(Xmid, Ymid, Color.Blue); + _api.GUILib.DrawPixel(X, Y, Color.Blue); + _api.GUILib.DrawPixel(X2, Y2, Color.Blue); + _api.GUILib.DrawPixel(X3, Y3, Color.Blue); + _api.GUILib.DrawPixel(X4, Y4, Color.Blue); + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + //Ecco head + Xpos = _api.MemLib.ReadS16(0xFFA8F8); + Xpos2 = _api.MemLib.ReadS16(0xFFA900); + Ypos = _api.MemLib.ReadS16(0xFFA8FC); + Ypos2 = _api.MemLib.ReadS16(0xFFA904); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); + //Ecco tail + Xpos = _api.MemLib.ReadS16(0xFFA978); + Xpos2 = _api.MemLib.ReadS16(0xFFA980); + Ypos = _api.MemLib.ReadS16(0xFFA97C); + Ypos2 = _api.MemLib.ReadS16(0xFFA984); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); + // sonar + if (_api.MemLib.ReadU8(0xFFAB77) != 0) + { + Xmid = _api.MemLib.ReadS16(0xFFA9EC); + Width2 = _api.MemLib.ReadS16(0xFFA9FC); + Xmid -= _camX; + Ymid = _api.MemLib.ReadS16(0xFFA9F0); + Ymid -= _camY; + Height2 = _api.MemLib.ReadS16(0xFFAA00); + color = ((_api.MemLib.ReadU8(0xFFAA0C) != 0) ? Color.FromArgb(255, 0, 127) : Color.FromArgb(0, 0, 255)); + DrawBoxMWH(Xmid, Ymid, Width2, Height2, color); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); + _api.GUILib.DrawPixel(Xmid, Ymid, color); + } + //Pulsar + curObj = _api.MemLib.ReadU24(0xFFCFD1); + if (curObj != 0) + { + // sbyte Blah = _api.MemLib.ReadU8(CardBoard + 0x15); + curObj += 0x26; + // if (!(Blah & 1)) + // CardBoard += 0x14; + for (int l = 0; l < 4; l++) + { + if (_api.MemLib.ReadU16(curObj + 0x12) != 0) + { + Xmid = _api.MemLib.ReadS16(curObj); + Ymid = _api.MemLib.ReadS16(curObj + 4); + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 0x30, 0x30, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); + _api.GUILib.DrawPixel(Xmid, Ymid, Color.Red); + } + curObj += 0x14; + } + } + } + + void EccoAutofire(bool on) + { + //Modif N - ECCO HACK - make caps lock (weirdly) autofire player 1's C key + uint charge; + uint mode = _api.MemLib.ReadU8(0xFFA555); + int frameCount = _api.EmuLib.FrameCount(); + int lagCount = _api.EmuLib.LagCount(); + switch (mode) + { + case 0x00: + if (on) + { + if (_api.MemLib.ReadU16(0xFFF342) == 0xFFFD) + _api.JoypadLib.Set("C", false, 1); + else + _api.JoypadLib.Set("C", true, 1); + } + break; + case 0xE6: + if (_api.MemLib.ReadU16(0xFFD5E8) == 0x00000002) { + Dictionary buttons = new Dictionary(); + buttons["B"] = !(buttons["C"] = false); + _api.JoypadLib.Set(buttons, 1); + } + else + { + Dictionary buttons = new Dictionary(); + buttons["B"] = !(buttons["C"] = true); + _api.JoypadLib.Set(buttons, 1); + } + break; + case 0xF6: + charge = _api.MemLib.ReadU8(0xFFB19B); + if (on) + { + if ((charge == 1) || (_prevCharge == 1) || !(_prevOn || (_api.MemLib.ReadU8(0xFFB19B) != 0))) + _api.JoypadLib.Set("B", true, 1); + else + _api.JoypadLib.Set("B", false, 1); + if ((_api.MemLib.ReadU16(0xFFB168) == 0x3800) && ((_api.MemLib.ReadU16(0xFFA7C8) % 2) != 0)) + _api.EmuLib.SetIsLagged(true); + _api.JoypadLib.Set("C", (_api.MemLib.ReadU16(0xFFA7C8) % 2) != 0, 1); + } + _prevCharge = charge; + break; + case 0x20: + case 0x28: + case 0xAC: + if (on) + { + _api.JoypadLib.Set("C", (_api.MemLib.ReadS8(0xFFAA6E) >= 11), 1); + } + break; + default: + break; + } + _prevOn = on; + } + public override void Init(IPluginAPI api) + { + base.Init(api); + _api.MemLib.SetBigEndian(); + string gameName = _api.GameInfoLib.GetRomName(); + if ((gameName == "ECCO - The Tides of Time (J) [!]") || + (gameName == "ECCO - The Tides of Time (U) [!]") || + (gameName == "ECCO - The Tides of Time (E) [!]")) + { + _mode = Modes.Ecco2; + _camXAddr = 0xFFAD9C; + _camYAddr = 0xFFAD9E; + EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); + } + else if ((gameName == "ECCO The Dolphin (J) [!]") || + (gameName == "ECCO The Dolphin (UE) [!]")) + + { + _mode = Modes.Ecco1; + _camXAddr = 0xFFB836; + _camYAddr = 0xFFB834; + EmuHawkPluginLibrary.SetGameExtraPadding(160,112,160,112); + } + else + { + _mode = Modes.disabled; + Running = false; + } + } + public override void PreFrameCallback() + { + if (_mode != Modes.disabled) + { + EccoAutofire(_api.JoypadLib.Get(1)["C"] != _api.JoypadLib.GetImmediate()["P1 C"]); + } + } + public override void PostFrameCallback() + { + uint frame = _api.MemLib.ReadU32(0xFFA524); + uint mode = _api.MemLib.ReadByte(0xFFA555); + switch (mode) { + case 0x20: + case 0x28: + case 0xAC: + EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); + EccoDrawBoxes(); + break; + case 0xF6: + EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + EccoDraw3D(); + break; + default: + EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + break; + } + _camX = _api.MemLib.ReadS16(_camXAddr)-160; + _camY = _api.MemLib.ReadS16(_camYAddr)-112; + if (frame <= _prevF) + _api.EmuLib.SetIsLagged(true); + _prevF = frame; + } + public override void LoadStateCallback(string name) + { + _prevF = _api.MemLib.ReadU32(0xFFA524); + } + } +} From 9874c496aca1875a67b905c0cc7e960d6accf377 Mon Sep 17 00:00:00 2001 From: upthorn Date: Wed, 5 Dec 2018 11:58:19 -0800 Subject: [PATCH 006/440] Minor revisions to plugin API --- .../plugins/PluginLibrary.Emu.cs | 85 ++++++++++++++++++- .../plugins/PluginLibrary.GUIDraw.cs | 31 ++++++- .../plugins/PluginLibrary.Joypad.cs | 10 ++- .../Plugins/Libraries/PluginLibrary.cs | 30 +++---- 4 files changed, 129 insertions(+), 27 deletions(-) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs index b205516989..b0ccf94061 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs @@ -226,7 +226,90 @@ namespace BizHawk.Client.Common { Global.Config.AutoMinimizeSkipping = enabled; } - + public object GetSettings() + { + if (Emulator is GPGX) + { + var gpgx = Emulator as GPGX; + return gpgx.GetSettings(); + } + else if (Emulator is LibsnesCore) + { + var snes = Emulator as LibsnesCore; + return snes.GetSettings(); + } + else if (Emulator is NES) + { + var nes = Emulator as NES; + return nes.GetSettings(); + } + else if (Emulator is QuickNES) + { + var quicknes = Emulator as QuickNES; + return quicknes.GetSettings(); + } + else if (Emulator is PCEngine) + { + var pce = Emulator as PCEngine; + return pce.GetSettings(); + } + else if (Emulator is SMS) + { + var sms = Emulator as SMS; + return sms.GetSettings(); + } + else if (Emulator is WonderSwan) + { + var ws = Emulator as WonderSwan; + return ws.GetSettings(); + } + else + { + return null; + } + } + public bool PutSettings(object settings) + { + if (Emulator is GPGX) + { + var gpgx = Emulator as GPGX; + return gpgx.PutSettings(settings as GPGX.GPGXSettings); + } + else if (Emulator is LibsnesCore) + { + var snes = Emulator as LibsnesCore; + return snes.PutSettings(settings as LibsnesCore.SnesSettings); + } + else if (Emulator is NES) + { + var nes = Emulator as NES; + return nes.PutSettings(settings as NES.NESSettings); + } + else if (Emulator is QuickNES) + { + var quicknes = Emulator as QuickNES; + return quicknes.PutSettings(settings as QuickNES.QuickNESSettings); + } + else if (Emulator is PCEngine) + { + var pce = Emulator as PCEngine; + return pce.PutSettings(settings as PCEngine.PCESettings); + } + else if (Emulator is SMS) + { + var sms = Emulator as SMS; + return sms.PutSettings(settings as SMS.SMSSettings); + } + else if (Emulator is WonderSwan) + { + var ws = Emulator as WonderSwan; + return ws.PutSettings(settings as WonderSwan.Settings); + } + else + { + return false; + } + } public void SetRenderPlanes(params bool[] luaParam) { if (Emulator is GPGX) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs index e6612ad7f7..2647c19a89 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Drawing.Imaging; using System.Windows.Forms; using System.IO; @@ -23,6 +24,22 @@ namespace BizHawk.Client.Common protected Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); protected int _defaultPixelFont = 1; // gens protected Padding _padding = new Padding(0); + protected ImageAttributes _attributes = new ImageAttributes(); + private System.Drawing.Drawing2D.CompositingMode _compositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; + + public virtual void ToggleCompositingMode() + { + _compositingMode = 1 - _compositingMode; + } + + public virtual ImageAttributes GetAttributes() + { + return _attributes; + } + public virtual void SetAttributes(ImageAttributes a) + { + _attributes = a; + } #region Gui API public virtual void Dispose() @@ -135,6 +152,7 @@ namespace BizHawk.Client.Common { try { + g.CompositingMode = _compositingMode; g.DrawBezier(GetPen(color ?? _defaultForeground), p1, p2, p3, p4); } catch (Exception) @@ -150,6 +168,7 @@ namespace BizHawk.Client.Common { try { + g.CompositingMode = _compositingMode; g.DrawBeziers(GetPen(color ?? _defaultForeground), points); } catch (Exception) @@ -188,6 +207,7 @@ namespace BizHawk.Client.Common h = Math.Max(y2, 0.1f); } + g.CompositingMode = _compositingMode; g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, w, h); var bg = background ?? _defaultBackground; @@ -217,6 +237,7 @@ namespace BizHawk.Client.Common g.FillEllipse(brush, x, y, width, height); } + g.CompositingMode = _compositingMode; g.DrawEllipse(GetPen(line ?? _defaultForeground), x, y, width, height); } catch (Exception) @@ -249,6 +270,7 @@ namespace BizHawk.Client.Common icon = new Icon(path); } + g.CompositingMode = _compositingMode; g.DrawIcon(icon, x, y); } catch (Exception) @@ -281,8 +303,10 @@ namespace BizHawk.Client.Common _imageCache.Add(path, img); } } + var destRect = new Rectangle(x, y, width ?? img.Width, height ?? img.Height); - g.DrawImage(img, x, y, width ?? img.Width, height ?? img.Height); + g.CompositingMode = _compositingMode; + g.DrawImage(img, destRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, _attributes); } } @@ -319,7 +343,8 @@ namespace BizHawk.Client.Common var destRect = new Rectangle(dest_x, dest_y, dest_width ?? source_width, dest_height ?? source_height); - g.DrawImage(img, destRect, source_x, source_y, source_width, source_height, GraphicsUnit.Pixel); + g.CompositingMode = _compositingMode; + g.DrawImage(img, destRect, source_x, source_y, source_width, source_height, GraphicsUnit.Pixel, _attributes); } } @@ -327,6 +352,7 @@ namespace BizHawk.Client.Common { using (var g = GetGraphics()) { + g.CompositingMode = _compositingMode; g.DrawLine(GetPen(color ?? _defaultForeground), x1, y1, x2, y2); } } @@ -341,6 +367,7 @@ namespace BizHawk.Client.Common { using (var g = GetGraphics()) { + g.CompositingMode = _compositingMode; var bg = background ?? _defaultBackground; if (bg.HasValue) { diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs index f09a1e5cb1..5eeb3ff1e6 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs +++ b/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs @@ -145,7 +145,7 @@ namespace BizHawk.Client.Common /*Eat it*/ } } - public void Set(string button, bool state, int? controller = null) + public void Set(string button, bool? state = null, int? controller = null) { try { @@ -154,8 +154,10 @@ namespace BizHawk.Client.Common { toPress = "P" + controller + " " + button; } - - Global.LuaAndAdaptor.SetButton(toPress, state); + if (state.HasValue) + Global.LuaAndAdaptor.SetButton(toPress, state.Value); + else + Global.LuaAndAdaptor.UnSet(toPress); Global.ActiveController.Overrides(Global.LuaAndAdaptor); } catch @@ -196,7 +198,7 @@ namespace BizHawk.Client.Common /*Eat it*/ } } - public void SetAnalog(string control, float value, object controller = null) + public void SetAnalog(string control, float? value = null, object controller = null) { try { diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs index 1396c77334..258cd128e3 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs +++ b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs @@ -14,7 +14,7 @@ namespace BizHawk.Client.EmuHawk public class PluginLibrary { // public LuaDocumentation Docs { get; } - public PluginLibrary(IEmulatorServiceProvider serviceProvider) + private void Register(IEmulatorServiceProvider serviceProvider) { // Docs.Clear(); @@ -37,23 +37,15 @@ namespace BizHawk.Client.EmuHawk foreach (var lib in libs) { - bool addLibrary = true; - //var attributes = lib.GetCustomAttributes(typeof(LuaLibraryAttribute), false); - //if (attributes.Any()) - //{ - // addLibrary = VersionInfo.DeveloperBuild || (attributes.First() as LuaLibraryAttribute).Released; - //} - - if (addLibrary) - { - var instance = (PluginLibraryBase)Activator.CreateInstance(lib); - //instance.LuaRegister(lib, Docs); - //instance.LogOutputCallback = ConsoleLuaLibrary.LogOutput; - ServiceInjector.UpdateServices(serviceProvider, instance); - Libraries.Add(lib, instance); - } + var instance = (PluginLibraryBase)Activator.CreateInstance(lib); + ServiceInjector.UpdateServices(serviceProvider, instance); + Libraries.Add(lib, instance); } } + public PluginLibrary(IEmulatorServiceProvider serviceProvider) + { + Register(serviceProvider); + } private readonly Dictionary Libraries = new Dictionary(); public List PluginList { get; } = new List(); @@ -68,10 +60,8 @@ namespace BizHawk.Client.EmuHawk public void Restart(IEmulatorServiceProvider newServiceProvider) { - foreach (var lib in Libraries) - { - ServiceInjector.UpdateServices(newServiceProvider, lib.Value); - } + Libraries.Clear(); + Register(newServiceProvider); foreach (var plugin in PluginList) { plugin.Init(new PluginAPI(Libraries)); From a13b9b3a317396568970c6a28b6563e6d68d99c5 Mon Sep 17 00:00:00 2001 From: upthorn Date: Wed, 5 Dec 2018 11:59:13 -0800 Subject: [PATCH 007/440] Significant updates to example Ecco 2 plugin. --- .../Plugins/Example/Ecco2AssistantPlugin.cs | 3454 +++++++++++++++-- 1 file changed, 3048 insertions(+), 406 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs b/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs index 753bc5d425..75a58dcd79 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs +++ b/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Drawing; +using System.Linq; using BizHawk.Client.Common; +using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; namespace BizHawk.Client.EmuHawk { @@ -19,102 +22,490 @@ namespace BizHawk.Client.EmuHawk private int _camY = 0; private int _camXAddr; private int _camYAddr; - private bool _prevOn = false; - private uint _prevCharge = 0; private uint _prevF = 0; - - void DrawEccoOct(int x, int y, int r, Color? color = null, int fillAlpha = 0) + private int _top = 0; + private int _bottom = 0; + private int _left = 0; + private int _right = 0; + private const int _signalAlpha = 255; + private int _tickerY = 81; + private int _dumpMap = 0; + private int _prevX = 0; + private int _prevY = 0; + private int _destX = 0; + private int _destY = 0; + private int _snapPast = 0; + private string _rowStateGuid = string.Empty; + private EmuHawkPluginLibrary _clientLib; + private Color[] _turnSignalColors = { - Point[] octPoints = { - new Point(x, y - r), - new Point((int)(x + Math.Sin(Math.PI / 4) * r), (int)(y - Math.Sin(Math.PI / 4) *r)), - new Point(x + r, y), - new Point((int)(x + Math.Sin(Math.PI / 4) * r), (int)(y + Math.Sin(Math.PI / 4) *r)), - new Point(x, y + r), - new Point((int)(x - Math.Sin(Math.PI / 4) * r), (int)(y + Math.Sin(Math.PI / 4) *r)), - new Point(x - r, y), - new Point((int)(x - Math.Sin(Math.PI / 4) * r), (int)(y - Math.Sin(Math.PI / 4) *r)) - }; - Color fillColor = color.HasValue ? Color.FromArgb(fillAlpha, color.Value) : Color.Empty; - _api.GUILib.DrawPolygon(octPoints, color, fillColor); + Color.FromArgb(_signalAlpha, 127, 127, 0), + Color.FromArgb(_signalAlpha, 255, 0, 0), + Color.FromArgb(_signalAlpha, 192, 0, 63), + Color.FromArgb(_signalAlpha, 63, 0, 192), + Color.FromArgb(_signalAlpha, 0, 0, 255), + Color.FromArgb(_signalAlpha, 0, 63, 192), + Color.FromArgb(_signalAlpha, 0, 192, 63), + Color.FromArgb(_signalAlpha, 0, 255, 0) + }; + private int _rseed = 1; + private int EccoRand(bool refresh = false) + { + if (refresh) + { + _rseed = (int)(_api.MemLib.ReadU16(0xFFE2F8)); + } + bool odd = (_rseed & 1) != 0; + _rseed >>= 1; + if (odd) + { + _rseed ^= 0xB400; + } + return _rseed; } - void DrawBoxMWH(int x, int y, int w, int h, Color? color = null, int fillAlpha = 0) + private void DrawEccoRhomb(int x, int y, int radius, Color color, int fillAlpha = 63) { - Color fillColor = color.HasValue ? Color.FromArgb(fillAlpha, color.Value) : Color.Empty; + Point[] rhombus = { + new Point(x, y - radius), + new Point(x + radius, y), + new Point(x, y + radius), + new Point(x - radius, y) + }; + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(rhombus, color, fillColor); + } + private void DrawEccoRhomb_scaled(int x, int y, int width, int height, int rscale, int bscale, int lscale, int tscale, Color color, int fillAlpha = 63) + { + Point[] rhombus = { + new Point(x + (width << rscale), y), + new Point(x, y + (height << bscale)), + new Point(x - (width << lscale), y), + new Point(x, y - (height << tscale)) + }; + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(rhombus, color, fillColor); + } + private void DrawEccoOct(int x, int y, int r, Color color, int fillAlpha = 63) + { + var octOff = (int)(Math.Sqrt(2) * r) >> 1; + Point[] octagon = { + new Point(x, y - r), + new Point(x + octOff, y - octOff), + new Point(x + r, y), + new Point(x + octOff, y + octOff), + new Point(x, y + r), + new Point(x - octOff, y + octOff), + new Point(x - r, y), + new Point(x - octOff, y - octOff) + }; + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(octagon, color, fillColor); + } + private void DrawEccoOct_scaled(int x, int y, int xscale, int yscale, int r, Color color, int fillAlpha = 63) + { + var octOff = (int)(Math.Sin(Math.PI / 4) * r); + var xoctOff = octOff << xscale; + var yoctOff = octOff << yscale; + var xr = r << xscale; + var yr = r << yscale; + Point[] octagon = { + new Point(x, y - yr), + new Point(x + xoctOff, y - yoctOff), + new Point(x + xr, y), + new Point(x + xoctOff, y + yoctOff), + new Point(x, y + yr), + new Point(x - xoctOff, y + yoctOff), + new Point(x - xr, y), + new Point(x - xoctOff, y - yoctOff) + }; + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(octagon, color, fillColor); + } + private Point? Intersection(Point start1, Point end1, Point start2, Point end2) + { + if ((Math.Max(start1.X, end1.X) < Math.Min(start2.X, end2.X)) + || (Math.Min(start1.X, end1.X) > Math.Max(start2.X, end2.X)) + || (Math.Max(start1.Y, end1.Y) < Math.Min(start2.Y, end2.Y)) + || (Math.Min(start1.Y, end1.Y) > Math.Max(start2.Y, end2.Y))) + return null; + + + double ay_cy, ax_cx, px, py; + double dx_cx = end2.X - start2.X, + dy_cy = end2.Y - start2.Y, + bx_ax = end1.X - start1.X, + by_ay = end1.Y - start1.Y; + + double de = (bx_ax) * (dy_cy) - (by_ay) * (dx_cx); + + if (Math.Abs(de) < 0.01) + return null; + + ax_cx = start1.X - start2.X; + ay_cy = start1.Y - start2.Y; + double r = ((ay_cy) * (dx_cx) - (ax_cx) * (dy_cy)) / de; + double s = ((ay_cy) * (bx_ax) - (ax_cx) * (by_ay)) / de; + px = start1.X + r * (bx_ax); + py = start1.Y + r * (by_ay); + if ((px < Math.Min(start1.X, end1.X)) || (px > Math.Max(start1.X, end1.X)) + || (px < Math.Min(start2.X, end2.X)) || (px > Math.Max(start2.X, end2.X)) + || (py < Math.Min(start1.Y, end1.Y)) || (py > Math.Max(start1.Y, end1.Y)) + || (py < Math.Min(start2.Y, end2.Y)) || (py > Math.Max(start2.Y, end2.Y))) + return null; + return new Point((int)px, (int)py); + } + private void DrawRectRhombusIntersection(Point rectMid, Point rhombMid, int rw, int rh, int r, Color color, int fillAlpha = 63) // Octagon provided by the intersection of a rectangle and a rhombus + { + Point[] rect = + { + new Point(rectMid.X - rw, rectMid.Y + rh), + new Point(rectMid.X - rw, rectMid.Y - rh), + new Point(rectMid.X + rw, rectMid.Y - rh), + new Point(rectMid.X + rw, rectMid.Y + rh) + }; + Point[] rhombus = + { + new Point(rhombMid.X - r, rhombMid.Y), + new Point(rhombMid.X, rhombMid.Y - r), + new Point(rhombMid.X + r, rhombMid.Y), + new Point(rhombMid.X, rhombMid.Y + r) + }; + List finalShape = new List(); + foreach (Point p in rect) + { + if (Math.Abs(p.X - rhombMid.X) + Math.Abs(p.Y - rhombMid.Y) <= r) + finalShape.Add(p); + } + foreach (Point p in rhombus) + { + if ((Math.Abs(p.X - rectMid.X) <= rw) && (Math.Abs(p.Y - rectMid.Y) <= rh)) + finalShape.Add(p); + } + for (int i = 0; i < 5; i++) + { + Point? p = Intersection(rhombus[i & 3], rhombus[(i + 1) & 3], rect[i & 3], rect[(i + 1) & 3]); + if (p.HasValue) finalShape.Add(p.Value); + p = Intersection(rhombus[i & 3], rhombus[(i + 1) & 3], rect[(i + 1) & 3], rect[(i + 2) & 3]); + if (p.HasValue) finalShape.Add(p.Value); + } + double mX = 0; + double my = 0; + foreach (Point p in finalShape) + { + mX += p.X; + my += p.Y; + } + mX /= finalShape.ToArray().Length; + my /= finalShape.ToArray().Length; + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(finalShape.OrderBy(p => Math.Atan2(p.Y - my, p.X - mX)).ToArray(), color, fillColor); + } + private void DrawEccoTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color, int fillAlpha = 63) + { + Color? fillColor = null; + Point[] triPoints = + { + new Point(x1, y1), + new Point(x2, y2), + new Point(x3, y3) + }; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawPolygon(triPoints, color, fillColor); + } + private void DrawBoxMWH(int x, int y, int w, int h, Color color, int fillAlpha = 63) + { + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); _api.GUILib.DrawRectangle(x - w, y - h, w << 1, h << 1, color, fillColor); } - void Print_Text(string message, int size, int x, int y, Color color) + private void DrawBox(int x, int y, int x2, int y2, Color color, int fillAlpha = 63) + { + Color? fillColor = null; + if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); + _api.GUILib.DrawBox(x, y, x2, y2, color, fillColor); + } + private void Print_Text(string message, int x, int y, Color color) { _api.GUILib.DrawText(x, y, message, color, null); } - void PutText(string message, int x, int y, int xl, int yl, int xh, int yh, Color bg, Color fg) + private void PutText(string message, int x, int y, int xl, int yl, int xh, int yh, Color bg, Color fg) { xl = Math.Max(xl, 0); - yl = Math.Max(xl, 0); + yl = Math.Max(yl, 0); xh = Math.Min(xh + 639, 639); yh = Math.Min(yh + 441, 441); xh -= 4 * message.Length; x = x - ((5 * (message.Length - 1)) / 2); - x = Math.Min(Math.Max(x, Math.Max(xl, 1)), Math.Min(xh, 638 - 4 * (int)message.Length)); - y = Math.Min(Math.Max(y - 3, Math.Max(yl, 1)), yh); + y -= 3; +// x = Math.Min(Math.Max(x, Math.Max(xl, 1)), Math.Min(xh, 638 - 4 * (int)message.Length)); +// y = Math.Min(Math.Max(y - 3, Math.Max(yl, 1)), yh); int[] xOffset = { -1, -1, -1, 0, 1, 1, 1, 0 }; int[] yOffset = { -1, 0, 1, 1, 1, 0, -1, -1 }; for (int i = 0; i < 8; i++) - Print_Text(message, message.Length, x + xOffset[i], y + yOffset[i], bg); - Print_Text(message, message.Length, x, y, fg); + Print_Text(message, x + xOffset[i], y + yOffset[i], bg); + Print_Text(message, x, y, fg); } - - - void EccoDraw3D() + private void TickerText(string message, Color? fg = null) { - int ScreenX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC); - int ScreenY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC); - int ScreenZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xB); + if (_dumpMap == 0) + _api.GUILib.Text(1, _tickerY, message, fg); + _tickerY += 16; + } + private void EccoDraw3D() + { + int CamX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC) - _left; + int CamY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC) + _top; + int CamZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xC) + _top; uint curObj = _api.MemLib.ReadU24(0xFFD4C1); while (curObj != 0) { int Xpos = (_api.MemLib.ReadS32(curObj + 0x6) >> 0xC); int Ypos = (_api.MemLib.ReadS32(curObj + 0xE) >> 0xC); - int Zpos = (_api.MemLib.ReadS32(curObj + 0xA) >> 0xB); - int Y = 224 - (Zpos - ScreenZ); - int X = (Xpos - ScreenX) + 0xA0; + int Zpos = (_api.MemLib.ReadS32(curObj + 0xA) >> 0xC); + int Xmid = 160 + (Xpos - CamX); + int Ymid = 112 - (Ypos - CamY); + int Zmid = _top + 112 - (Zpos - CamZ); uint type = _api.MemLib.ReadU32(curObj + 0x5A); - short height, width; - int display = 0; - if ((type == 0xD817E) || (type == 0xD4AB8)) + int width, height, depth = height = width = 0; + if (type == 0xD4AB8) // 3D poison Bubble { - Y = 113 - (Ypos - ScreenY); - height = 0x10; - if (_api.MemLib.ReadU32(0xFFB166) < 0x1800) height = 0x8; - short radius = 31; - if (type == 0xD4AB8) - { - radius = 7; - height = 0x20; - } + depth = 0x10; + int radius = 8; width = radius; - DrawEccoOct(X, Y, radius, Color.Lime, 0); - display = 1; + DrawEccoOct(Xmid, Ymid, radius, Color.Lime); + DrawBoxMWH(Xmid, Zmid, width, depth, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + } + else if (type == 0xD817E)// 3D Ring + { + depth = 8; + if (_api.MemLib.ReadU32(0xFFB166) < 0x1800) depth = 4; + int radius = 32; + width = radius; + DrawEccoOct(Xmid, Ymid, radius, (_api.MemLib.ReadS16(curObj + 0x62) == 0) ? Color.Orange : Color.Gray); + DrawBoxMWH(Xmid, Zmid, width, depth, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red, 0); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x6) / 4096.0:0.######}:{_api.MemLib.ReadS32(curObj + 0xE) / 4096.0:0.######}:{_api.MemLib.ReadS32(curObj + 0xA) / 2048.0:0.######}:{_api.MemLib.ReadByte(curObj + 0x72)}",Color.Lime); + } + else if (type == 0xD49CC) // Vines collisions are based on draw position, which is a fucking pain in the ass to calculate + { + int Xvel = (_api.MemLib.ReadS32(curObj + 0x3A) - _api.MemLib.ReadS32(curObj + 0x6)); + int Zvel = (_api.MemLib.ReadS32(curObj + 0x3E) - _api.MemLib.ReadS32(curObj + 0xA)); + int dx = _api.MemLib.ReadS32(0xFFD5E0) - _api.MemLib.ReadS32(0xFFD5C8) >> 3; + int dy = _api.MemLib.ReadS32(0xFFD5E8) - _api.MemLib.ReadS32(0xFFD600) >> 3; + int dz = _api.MemLib.ReadS32(0xFFD5E4) - _api.MemLib.ReadS32(0xFFD5CC); + var chargeCount = _api.MemLib.ReadByte(0xFFB19B); + if (chargeCount == 0) + { + dz >>= 2; + } + else if ((chargeCount > 0x20) || (chargeCount <= 0x10)) + { + dz >>= 3; + } + else if (chargeCount > 0x10) + { + dz >>= 4; + } + if (_api.MemLib.ReadByte(curObj + 0x64) == 0) + { + Xvel >>= 0xA; + Zvel >>= 9; + } + else + { + Xvel >>= 9; + Zvel >>= 0xA; + } + Xvel += _api.MemLib.ReadS32(curObj + 0x2E); + Zvel += _api.MemLib.ReadS32(curObj + 0x32); + Zpos = (_api.MemLib.ReadS32(curObj + 0x26) + dz - _api.MemLib.ReadS32(0xFFD5E4)) >> 0xB; + if ((Zpos < 0x600) && (Zpos > 0)) + { + Zpos += 0x20; + int Xcur, Xmax, Ycur, Ymax; + int Zpos2 = (_api.MemLib.ReadS32(curObj + 0xA) + Zvel + dz - _api.MemLib.ReadS32(0xFFD5E4)) >> 0xB; + Zpos2 = Math.Max(Zpos2 + 0x20, 1); + if (_api.MemLib.ReadS16(curObj + 0x62) != 0) + { + Xmid = _api.MemLib.ReadS32(curObj + 0x6) + dx + Xvel - _api.MemLib.ReadS32(0xFFD5E0); + if (Math.Abs(Xmid) > 0x400000) + continue; + Xpos = _api.MemLib.ReadS32(curObj + 0x22) + dx - _api.MemLib.ReadS32(0xFFD5E0); + if (Math.Abs(Xpos) > 0x400000) + continue; + Xcur = (Xmid << 2) / Zpos2 + (Xmid >> 5) + 0xA000 + (Xmid >> 5); + Xmax = (Xpos << 2) / Zpos + (Xpos >> 5) + 0xA000 + (Xpos >> 5); + } + else + { + Xcur = 0; + Xmax = 256; + } + Ymid = _api.MemLib.ReadS32(0xFFD5E8) + dy - _api.MemLib.ReadS32(curObj + 0xE); + Ycur = ((Ymid << 3) / Zpos2) + 0x6000; + Ypos = _api.MemLib.ReadS32(0xFFD5E8) + dy - _api.MemLib.ReadS32(curObj + 0x2A); + Ymax = ((Ypos << 3) / Zpos) + 0x6000; + dx = Xmax - Xcur; + dy = Ymax - Ycur; + int asindx = Math.Abs(dx >> 6) & 0xFFFF; + int asindy = Math.Abs(dy >> 6) & 0xFFFF; + int ang; + if (asindx == asindy) + { + if (dx > 0) + { + if (dy > 0) + { + ang = 0x20; + } + else + { + ang = 0xE0; + } + } + else + { + if (dy > 0) + { + ang = 0x60; + } + else + { + ang = 0xA0; + } + } + } + else + { + if (asindx > asindy) + { + asindy <<= 5; + asindy += asindx - 1; + asindy &= 0xFFFF; + asindy /= asindx; + } + else + { + asindx <<= 5; + asindx += asindy - 1; + asindx &= 0xFFFF; + asindx /= asindy; + asindy = 0x40 - asindx; + } + if (dx > 0) + { + if (dy > 0) + { + ang = asindy; + } + else + { + ang = 0xff - asindy; + } + } + else + { + if (dy > 0) + { + ang = 0x7f - asindy; + } + else + { + ang = 0x81 + asindy; + } + } + } + Xcur += _api.MemLib.ReadS8(0x2CC8 + ang) << 6; + Ycur += _api.MemLib.ReadS8(0x2BC8 + ang) << 6; + var dSml = Math.Abs(dx); + var dBig = Math.Abs(dy); + if (dBig < dSml) + { + dSml ^= dBig; + dBig ^= dSml; + dSml ^= dBig; + } + int OctRad = (dBig + (dSml >> 1) - (dSml >> 3)); + int i = Math.Max(((OctRad >> 8) + 0x1F) >> 5, 1); + dx /= i; + dy /= i; + + Zmid = (_api.MemLib.ReadS32(curObj + 0xA) + _api.MemLib.ReadS32(curObj + 0x26)) >> 1; + Zmid >>= 0xC; + Zmid = 112 + _top - (Zmid - CamZ); + do + { + i--; + DrawEccoRhomb((Xcur >> 8) + _left, (Ycur >> 8) + _top, 8, Color.Lime); + DrawBoxMWH((Xcur >> 8) + _left, Zmid, 8, 0x10, Color.Blue); + Xcur += dx; + Ycur += dy; + } while (i >= 0); + DrawBoxMWH((_api.MemLib.ReadS32(0xFFB1AA) >> 8) + _left, (_api.MemLib.ReadS32(0xFFB1AE) >> 8) + _top, 1, 1, Color.Lime, 0); + } + } + else if ((type == 0xD3B40) || (type == 0xD3DB2)) // 3D Shark and Jellyfish + { + width = (_api.MemLib.ReadS32(curObj + 0x12) >> 0xC); + height = (_api.MemLib.ReadS32(curObj + 0x1A) >> 0xC); + depth = (_api.MemLib.ReadS32(curObj + 0x16) >> 0xC); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); + DrawBoxMWH(Xmid, Zmid, width, depth, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + } + else if ((type == 0xD4028) || (type == 0xD4DBA)) // 3D Eagle and 3D Shell + { + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + } + else if (type == 0xD4432) // 3D Sonar Blast + { + DrawEccoOct(Xmid, Ymid, 48, Color.Orange); + DrawEccoOct(Xmid, Ymid, 32, Color.Lime); + DrawBoxMWH(Xmid, Zmid, 32, 32, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + } + else if (type == 0xD463A) // 3D Homing Bubble + { + DrawEccoOct(Xmid, Ymid, 48, Color.Orange); + DrawEccoOct(Xmid, Ymid, 32, Color.Lime); + DrawBoxMWH(Xmid, Zmid, 32, 32, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + } + else if ((type == 0xD37CE) || (type == 0xD4214) || (type == 0xD3808)) // bubbles, splashes, gfx sprites + { + width = height = depth = 0; } else { - width = height = 1; - if (curObj == 0xFFB134) display = 3; - } - if ((display & 1) != 0) - { - Y = 224 - (Zpos - ScreenZ); - DrawBoxMWH(X, Y, width, height, Color.Blue, 0); - } - if ((display & 2) != 0) - { - Y = 113 - (Ypos - ScreenY); - DrawBoxMWH(X, Y, width, height, Color.Lime, 0); + if (curObj != 0xFFB134) + { + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); + PutText(type.ToString("X8"), Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); + PutText(curObj.ToString("X8"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); + } + else + { + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange); + DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red); + } } curObj = _api.MemLib.ReadU24(curObj+1); } } - void EccoDrawBoxes() + private void EccoDrawBoxes() { // CamX-=8; int Width2, Height2; @@ -131,59 +522,74 @@ namespace BizHawk.Client.EmuHawk i++; off += 448; } color = Color.FromArgb(j >> 2, j >> 2, j >> 2); - _api.GUILib.DrawLine(128, j - off, 144, j - off, color); + _api.GUILib.DrawLine(_left - 32, j - off, _left - 17, j - off, color); + } + for (int j = 0; j < HP; j += 8) + { + color = Color.FromArgb(Math.Max(0x38 - (j >> 3),0), 0, Math.Min(j >> 1,255)); + _api.GUILib.DrawRectangle(_left - 16, j, 15, 7, color, color); } - for (i = 0; i < 16; i++) - for (int j = 0; j < Math.Min(HP, 448); j++) - { - color = Color.FromArgb(0, 0, (j>>1 & 0xF0)); - _api.GUILib.DrawPixel(144 + i, j, color); - } //Asterite - uint curObj = _api.MemLib.ReadU24(0xFFCFC9); + uint type = _api.MemLib.ReadU32(0xFFD440); + uint curObj = 0; int Xpos, Xpos2, Ypos, Ypos2, Xmid, Ymid, X, X2, Y, Y2; - Xmid = 0; - Ymid = 0; - while (curObj != 0) + Xpos = Ypos = Xpos2 = Ypos2 = Xmid = Ymid = X = X2 = Y = Y2 = 0; + if (type == 0xB119A) { - if (_api.MemLib.ReadU32(curObj + 8) != 0) + curObj = _api.MemLib.ReadU24(_api.MemLib.ReadU24(0xFFD429)+5); + while (curObj != 0) { Xpos = _api.MemLib.ReadS16(curObj + 0x3C); - Xpos2= _api.MemLib.ReadS16(curObj + 0x24); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x24); Ypos = _api.MemLib.ReadS16(curObj + 0x40); - Ypos2= _api.MemLib.ReadS16(curObj + 0x28); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; if (_api.MemLib.ReadU8(curObj + 0x71) != 0) { - DrawEccoOct(Xpos, Ypos, 40, Color.FromArgb(255, 192, 0), 0x7F); - DrawEccoOct(Xpos2, Ypos2, 40, Color.FromArgb(255, 192, 0), 0x7F); + DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); + DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); + } + curObj = _api.MemLib.ReadU24(curObj + 5); + } + if ((_api.MemLib.ReadU8(0xFFA7D0) == 30)) + { + curObj = _api.MemLib.ReadU24(0xFFD425); + if ((curObj != 0) && (_api.MemLib.ReadU32(curObj + 8) != 0)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawEccoOct(Xpos, Ypos, 20, Color.Orange); } } - else - { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - } - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(0, Ymid-5), 424), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(2, Ymid-3), 426), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(2, Ymid-3), 426), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(0, Ymid-5), 424), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(1, Xmid-15), 606), Math.Min(Math.Max(1, Ymid-4), 425), Color.Blue); - curObj = _api.MemLib.ReadU24(curObj+1); } - uint curlev = _api.MemLib.ReadU8(0xFFA7E0); - if ((_api.MemLib.ReadU8(0xFFA7D0) == 30)) + else if (type == 0xB2CB8) { - curObj = _api.MemLib.ReadU24(0xFFD425); - if ((curObj != 0) && (_api.MemLib.ReadU32(curObj + 8) != 0)) + curObj = _api.MemLib.ReadU24(_api.MemLib.ReadU24(0xFFD429) + 5); + while (curObj != 0) { - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; - DrawEccoOct(Xpos, Ypos, 20, Color.FromArgb(255, 192, 0)); + Xpos = _api.MemLib.ReadS16(curObj + 0x3C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x24); + Ypos = _api.MemLib.ReadS16(curObj + 0x40); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + if (_api.MemLib.ReadU8(curObj + 0x71) != 0) + { + if (_api.MemLib.ReadByte(0xFFA7D0) != 0x1F) + { + DrawEccoOct(Xpos, Ypos, 40, Color.Lime); + DrawEccoOct(Xpos2, Ypos2, 40, Color.Lime); + } + DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); + DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); + } + curObj = _api.MemLib.ReadU24(curObj + 5); } } //aqua tubes @@ -199,254 +605,408 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; // displayed = false; - uint type = _api.MemLib.ReadU8(curObj + 0x7E); - int yoff = 0; + type = _api.MemLib.ReadU8(curObj + 0x7E); switch (type) { - /* case 0x11: - Xpos2 = Xmid; - Xmid = (Xpos + Xpos2) >> 1; - break; - case 0x12: - Xpos = Xmid; - Xmid = (Xpos + Xpos2) >> 1; - break; - case 0x13: - Ypos = Ymid; - Ymid = (Ypos + Ypos2) >> 1; - break; - case 0x14: - Ypos2 = Ymid; - Ymid = (Ypos + Ypos2) >> 1; - break;*/ case 0x15: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) - _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid + yoff, Color.FromArgb(127, 0, 255)); - for (int TempX = Math.Min(Math.Max(0, Xmid), 320); TempX <= Math.Min(Math.Max(8, Xpos2), 327); TempX++) - _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); - for (uint TempX = (uint)Math.Min(Math.Max(0, Ymid), 223); TempX <= Math.Min(Math.Max(0, Ypos2), 223); TempX++) - _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); - break; case 0x18: case 0x19: - for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) - { - _api.GUILib.DrawPixel(Xmid + yoff, Ypos2-TempX, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.Purple); break; case 0x1A: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) - _api.GUILib.DrawPixel(Xpos + TempX, Ymid + yoff, Color.FromArgb(127, 0, 255)); - for (int TempX = Math.Min(Math.Max(0, Xpos), 320); TempX <= Math.Min(Math.Max(8, Xmid), 327); TempX++) - _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); - for (uint TempX = (uint)Math.Min(Math.Max(0, Ymid), 223); TempX <= Math.Min(Math.Max(0, Ypos2), 223); TempX++) - _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); - break; case 0x1D: - for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) - { - _api.GUILib.DrawPixel(Xmid - yoff, Ypos2 - TempX, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } - break; - case 0x1F: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) - _api.GUILib.DrawPixel(Xpos + TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); - for (int TempX = Math.Min(Math.Max(0, Xpos), 320); TempX <= Math.Min(Math.Max(8, Xmid), 327); TempX++) - _api.GUILib.DrawPixel(TempX, Ymid, Color.FromArgb(127, 0, 255)); - for (uint TempX = (uint)Math.Min(Math.Max(0, Ypos), 223); TempX <= Math.Min(Math.Max(0, Ymid), 223); TempX++) - _api.GUILib.DrawPixel(Xmid, (int)TempX, Color.FromArgb(127, 0, 255)); - break; case 0x20: case 0x21: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++) - { - _api.GUILib.DrawPixel(Xpos + TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.Purple); break; + case 0x1F: case 0x22: case 0x23: - for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) - { - _api.GUILib.DrawPixel(Xmid - yoff, Ypos + TempX, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.Purple); break; case 0x24: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++, yoff++) - _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); - break; case 0x25: case 0x26: - for (int TempX = 0; TempX <= Xmid-Xpos; TempX++) - { - _api.GUILib.DrawPixel(Xpos2 - TempX, Ymid - yoff, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } - break; case 0x27: case 0x28: - for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) - { - _api.GUILib.DrawPixel(Xmid + yoff, Ypos + TempX, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.Purple); break; case 0x2B: - _api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.FromArgb(127, 0, 255)); - for (int TempX = 0; TempX <= Ymid - Ypos; TempX++) - { - _api.GUILib.DrawPixel(Xpos + yoff, Ymid - TempX, Color.FromArgb(127, 0, 255)); - _api.GUILib.DrawPixel(Xpos2 - yoff, Ymid - TempX, Color.FromArgb(127, 0, 255)); - if ((TempX & 1) != 0) yoff++; - } - yoff = Xmid - (Xpos + yoff); - _api.GUILib.DrawLine(Xmid - yoff, Ypos, Xmid + yoff, Ypos, Color.FromArgb(127, 0, 255)); + Point[] trapPoints = + { + new Point(Xpos, Ymid), + new Point(Xpos + (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2, Ymid) + }; + _api.GUILib.DrawPolygon(trapPoints, Color.Purple, Color.FromArgb(63, Color.Purple)); break; default: - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(255, 127, 0, 255)); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Purple); + if (type != 0x10) + PutText(type.ToString("X2"), Xmid, Ymid, 1, 1, -1, -1, Color.Red, Color.Blue); break; } - // if (!displayed) - if (type != 0x10) - { - uint temp = _api.MemLib.ReadU8(curObj + 0x7E); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(1, Xmid-2), 629), Math.Min(Math.Max(1, Ymid-4), 425), Color.Blue); - } curObj = _api.MemLib.ReadU24(curObj+1); } //walls - bool displayed; curObj = _api.MemLib.ReadU24(0xFFCFC1); while (curObj != 0) { - + Xmid = _api.MemLib.ReadS16(curObj + 0x24); + Xmid = _api.MemLib.ReadS16(curObj + 0x28); Xpos = _api.MemLib.ReadS16(curObj + 0x2C); Xpos2= _api.MemLib.ReadS16(curObj + 0x34); Ypos = _api.MemLib.ReadS16(curObj + 0x30); Ypos2= _api.MemLib.ReadS16(curObj + 0x38); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - displayed = false; - uint type = _api.MemLib.ReadU8(curObj + 0x7E); - int yoff = 0; - switch (type) + Xmid -= _camX; Ymid -= _camY; + int colltype = _api.MemLib.ReadS8(curObj + 0x7E); + switch (colltype) { + case 0x10: + case 0x2D: + case 0x2E: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; case 0x11: - Xpos2 = Xmid; Xmid = (Xpos + Xpos2) >> 1; + Xpos2 = Xmid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.PowderBlue); break; case 0x12: - Xpos = Xmid; Xmid = (Xpos + Xpos2) >> 1; + Xpos = Xmid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos, Ypos2, Color.PowderBlue); break; case 0x13: - Ypos = Ymid; Ymid = (Ypos + Ypos2) >> 1; + Ypos = Ymid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.PowderBlue); break; case 0x14: - Ypos2 = Ymid; Ymid = (Ypos + Ypos2) >> 1; + Ypos2 = Ymid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.PowderBlue); break; case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: - _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.White); - _api.GUILib.DrawLine(Xmid, Ypos2, Xmid, Ymid, Color.FromArgb(127,Color.White)); - _api.GUILib.DrawLine(Xmid, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); - displayed = true; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); break; case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.White); - _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ypos2, Color.FromArgb(127, Color.White)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ymid, Color.FromArgb(127, Color.White)); - displayed = true; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); break; case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23: - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.White); - _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ypos, Color.FromArgb(127, Color.White)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ymid, Color.FromArgb(127, Color.White)); - displayed = true; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63,Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); break; case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: - _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.White); - _api.GUILib.DrawLine(Xmid, Ypos, Xmid, Ymid, Color.FromArgb(127, Color.White)); - _api.GUILib.DrawLine(Xmid, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); - displayed = true; + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63,Color.Yellow)); + _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); + break; + case 0x29: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); + _api.GUILib.DrawLine(Xpos , Ypos, Xpos , Ypos2, Color.Black); + _api.GUILib.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.Black); + break; + case 0x2A: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); break; case 0x2B: - _api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.FromArgb(127, Color.White)); - for (int TempX = 0; TempX <= Ymid-Ypos; TempX++) + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + Point[] trapPoints = { - _api.GUILib.DrawPixel(Xpos + yoff, Ymid - TempX, Color.White); - _api.GUILib.DrawPixel(Xpos2 - yoff, Ymid - TempX, Color.White); - if ((TempX & 1) != 0) yoff++; - } - yoff = Xmid - (Xpos + yoff); - _api.GUILib.DrawLine(Xmid - yoff, Ypos, Xmid + yoff, Ypos); - displayed = true; + new Point(Xpos, Ymid), + new Point(Xpos + (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2, Ymid) + }; + _api.GUILib.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); + //_api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.Yellow); break; default: - if (type != 0x10) - { - var temp = _api.MemLib.ReadU8(curObj + 0x7E); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(0, Xmid-3), 628), Math.Min(Math.Max(2, Ymid-3), 426), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(2, Xmid-1), 630), Math.Min(Math.Max(0, Ymid-5), 424), Color.Red); - Print_Text(temp.ToString("%02X"), 2, Math.Min(Math.Max(1, Xmid-2), 629), Math.Min(Math.Max(1, Ymid-4), 425), Color.Lime); - } + DrawEccoRhomb_scaled(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); break; } - if (!displayed) _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); curObj = _api.MemLib.ReadU24(curObj+1); } //inanimate objects curObj = _api.MemLib.ReadU24(0xFFCFBD); while (curObj != 0) { - if (_api.MemLib.ReadU8(curObj + 0x7E) > 0xF); + type = _api.MemLib.ReadU32(curObj + 0xC); + int colltype = _api.MemLib.ReadS8(curObj + 0x7E); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + int Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + int Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + if (type == 0x9CE3A) //Remnant Stars { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2= _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2= _api.MemLib.ReadS16(curObj + 0x38); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - } - Xpos += Xpos2; - Ypos += Ypos2; - Xpos >>= 1; - Ypos >>= 1; - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xpos-16), 605), Math.Min(Math.Max(0, Ypos-5), 424), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xpos-14), 607), Math.Min(Math.Max(2, Ypos-3), 426), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(0, Xpos-16), 605), Math.Min(Math.Max(2, Ypos-3), 426), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(2, Xpos-14), 607), Math.Min(Math.Max(0, Ypos-5), 424), Color.Lime); - Print_Text(curObj.ToString("X8"), 8, Math.Min(Math.Max(1, Xpos-15), 606), Math.Min(Math.Max(1, Ypos-4), 425), Color.Blue); - curObj = _api.MemLib.ReadU24(curObj+1); + uint subObj = _api.MemLib.ReadU24(curObj + 0x5); + uint anim = _api.MemLib.ReadU16(curObj + 0x6C); + if ((anim <= 7) && (subObj == 0xFFA9D4)) + { + DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); + PutText($"{((7 - anim) * 4) - ((_api.MemLib.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Lime, Color.Blue); + } + } + else if ((type == 0x9CC06) || (type == 0x9CA10)) + { + Xvec = ((_api.MemLib.ReadS32(curObj + 0x24) + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((_api.MemLib.ReadS32(curObj + 0x28) + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + } + else if (type == 0x9B5D8) + { + Xvec = Xmid; + Yvec = Ymid; + } + else if (type == 0xC0152) // Vortex Future Vertical Gate + { + Xvec = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Yvec = (_api.MemLib.ReadS32(curObj + 0x20) + _api.MemLib.ReadS32(curObj + 0x60) >> 16) - _camY; + _api.GUILib.DrawLine(Xmid, 0, Xmid, 448, Color.PowderBlue); + DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + } + else if (type == 0xC3330) // City Of Forever Horizontal Gate Slave + { + Xvec = (_api.MemLib.ReadS32(curObj + 0x1C) + _api.MemLib.ReadS32(curObj + 0x5C) >> 16) - _camX; + Yvec = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + } + else if (type == 0xC35B0) // City Of Forever Horizontal Gate Master + { + var mode = _api.MemLib.ReadByte(curObj + 0x15); + var tmpx = Xpos; + Xpos = _api.MemLib.ReadS32(curObj + 0x1C); + Xvec = (Xpos + _api.MemLib.ReadS32(curObj + 0x5C) >> 16) - _camX; + Xpos >>= 16; Xpos -= _camX; + Yvec = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + if ((mode == 1) || (mode == 3)) + { + DrawEccoOct(Xpos, Yvec, 128, Color.Orange); + } + Xpos = tmpx; + DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + } + else if (type == 0xC343A) // City Of Forever Vertical Gate + { + var mode = _api.MemLib.ReadByte(curObj + 0x15); + if ((mode == 1) || (mode == 3)) + { + DrawEccoOct(Xmid, Ymid, 128, Color.Orange); + } + Xvec = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Yvec = (_api.MemLib.ReadS32(curObj + 0x20) + _api.MemLib.ReadS32(curObj + 0x60) >> 16) - _camY; + DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + } + else if (type == 0xA579A) // Antigrav Ball + { + DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x4C), (_api.MemLib.ReadU16(0xFFA7C8) & 7) == 7 ? Color.Blue : Color.Gray); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); + Xpos = Ypos = Xpos2 = Ypos2 = _camX - 128; + } + else if (type == 0xDF4E2) // Moray Abyss Conch Shell + { + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawBox(Xpos - 96, 0 - _camY, Xpos + 96, _api.MemLib.ReadS16(0xFFA7AC) - _camY - 64, Color.Orange, 0); + var mode = _api.MemLib.ReadByte(curObj + 0x15); + var modeTimer = _api.MemLib.ReadS16(curObj + 0x6E); + var Xvel1 = _api.MemLib.ReadS32(curObj + 0x54) / 65536.0; + var Yvel1 = _api.MemLib.ReadS32(curObj + 0x58) / 65536.0; + var Xvel2 = _api.MemLib.ReadS32(curObj + 0x5C) / 65536.0; + var Yvel2 = _api.MemLib.ReadS32(curObj + 0x60) / 65536.0; + TickerText($"{mode}:{modeTimer}:{_api.MemLib.ReadS16(0xFFA7AC) - 64 - Ymid - _camY}", Color.Red); + TickerText($"{Xvel1:0.######}:{Yvel1:0.######}", Color.Red); + TickerText($"{Xvel2:0.######}:{Yvel2:0.######}", Color.Red); + TickerText($"{Xvel1 + Xvel2:0.######}:{Yvel1 + Yvel2:0.######}", Color.Red); + switch (mode) + { + case 0: + Xpos2 = Math.Abs(Xmid - Xpos); + if (Xpos2 > 0x48) + { + Xpos2 = (0x60 - Xpos2) << 1; + Ypos2 = Ymid + Xpos2; + } + else + { + Ypos2 = Ymid - (Xpos2 >> 1) + 0x60; + } + DrawBoxMWH(Xpos, Ypos2, 1, 1, Color.Gray, 0); + DrawBoxMWH(Xpos, 112 + _top, 72, 224, (modeTimer <= 1) ? Color.Orange : Color.Gray, 0); + break; + case 1: + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Orange, 0); + Xpos2 = _api.MemLib.ReadS32(0xFFAA1A) - _api.MemLib.ReadS32(curObj + 0x24); + Ypos2 = _api.MemLib.ReadS32(0xFFAA1E) - _api.MemLib.ReadS32(curObj + 0x28); + var dSml = Math.Abs(Xpos2); + var dBig = Math.Abs(Ypos2); + if (dBig < dSml) + { + dSml ^= dBig; + dBig ^= dSml; + dSml ^= dBig; + } + var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; + Xpos2 = (int)(Xpos2 * (256.0 / (rad+1))) >> 20; + Ypos2 = (int)(Ypos2 * (256.0 / (rad+1))) >> 20; + _api.GUILib.DrawLine(Xmid, Ymid, Xmid + Xpos2, Ymid + Ypos2, Color.Gray); + TickerText($"{Xpos2 / 512.0:0.######}:{Ypos2 / 512.0:0.######}", Color.Red); + break; + case 2: + TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); + break; + } + } + else if ((type == 0xC57A6) || (type == 0xDEE3C) || (type == 0xDF8A0) || (type == 0xDFA98) + || (type == 0xA0BE4) || (type == 0x9FEB2) || (type == 0xA5670) || (type == 0xAEC1A) + || (type == 0xA6C4A) || (type == 0xAB65A) || (type == 0x9F2EC)) { } + else + { + PutText($"{type:X5}:{_api.MemLib.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.Lime, Color.Blue); + PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.Lime, Color.Blue); + } + colltype = _api.MemLib.ReadS8(curObj + 0x7E); + switch (colltype) + { + case 0x10: + case 0x2D: + case 0x2E: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; + case 0x11: + Xmid = (Xpos + Xpos2) >> 1; + Xpos2 = Xmid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; + case 0x12: + Xmid = (Xpos + Xpos2) >> 1; + Xpos = Xmid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; + case 0x13: + Ymid = (Ypos + Ypos2) >> 1; + Ypos = Ymid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; + case 0x14: + Ymid = (Ypos + Ypos2) >> 1; + Ypos2 = Ymid; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); + break; + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); + break; + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); + _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); + break; + case 0x2A: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); + break; + case 0x2B: + Xmid = (Xpos + Xpos2) >> 1; + Ymid = (Ypos + Ypos2) >> 1; + Point[] trapPoints = + { + new Point(Xpos, Ymid), + new Point(Xpos + (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), + new Point(Xpos2, Ymid) + }; + _api.GUILib.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); + break; + case 0x2C: + break; + default: + DrawEccoRhomb_scaled(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); + break; + } + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + curObj = _api.MemLib.ReadU24(curObj+1); } //animate objects if (_mode == Modes.Ecco2) @@ -455,78 +1015,1416 @@ namespace BizHawk.Client.EmuHawk curObj = _api.MemLib.ReadU24(0xFFD829); while (curObj != 0) { - uint type = 0; + type = 0; switch (_mode) { case Modes.Ecco2: - { - uint flags = _api.MemLib.ReadU16(curObj + 0x10); - //if ((flags & 0x2000) || !(flags & 2)); - type = _api.MemLib.ReadU32(curObj + 0xC); - if ((type == 0xBA52E) || (type == 0xBA66E)) { - uint Adelikat = curObj; - while (Adelikat != 0) + uint flags = _api.MemLib.ReadU16(curObj + 0x10); + int Xvec = 0; + int Yvec = 0; + //if ((flags & 0x2000) || !(flags & 2)); + HP = _api.MemLib.ReadS8(curObj + 0x7B); + type = _api.MemLib.ReadU32(curObj + 0xC); + if ((type == 0xA1FE6) || (type == 0xA208E) // Chain link creatures such as vortex worm, magic arm, etc + || (type == 0xA2288) || (type == 0xA27A4) || (type == 0xA2BB0) || (type == 0xA2C50)) { - Xpos = _api.MemLib.ReadS16(Adelikat + 0x24); - Ypos = _api.MemLib.ReadS16(Adelikat + 0x28); + uint subObj = curObj; + while (subObj != 0) + { + Xpos = _api.MemLib.ReadS32(subObj + 0x24); + Ypos = _api.MemLib.ReadS32(subObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; + Ypos -= _camY; + if (_api.MemLib.ReadS16(subObj + 0x44) == _api.MemLib.ReadS16(subObj + 0x48)) + { + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Cyan, 0); + } + else + { + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Lime, 0); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.Blue, 0); + } + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + subObj = _api.MemLib.ReadU24(subObj + 5); + } + if (HP > 2) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); + } + } + else if ((type == 0xB7486) || (type == 0xB864E) //Chain link creatures such as eels and worms + || (type == 0xB8A64) || (type == 0xB8C1A) + || (type == 0xB904A) || (type == 0xB9728) || (type == 0xB9B6A) || (type == 0xBA52E) + || (type == 0xBA66E) || (type == 0xE0988) || (type == 0xA18E2) || (type == 0xE069A)) + { + uint subObj = curObj; + while (subObj != 0) + { + Xpos = _api.MemLib.ReadS32(subObj + 0x24); + Ypos = _api.MemLib.ReadS32(subObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; + Ypos -= _camY; + if (_api.MemLib.ReadS16(subObj + 0x44) == _api.MemLib.ReadS16(subObj + 0x48)) + { + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.White, 0); + } + else + { + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Lime, 0); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.Magenta, 0); + } + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + if (type == 0xBA66E) + { + DrawEccoOct(Xpos, Ypos, 32, Color.Blue, 16); + if (subObj == curObj) + { + var mode = _api.MemLib.ReadByte(subObj + 0x15); + TickerText($"{_api.MemLib.ReadByte(subObj + 0x14)}:{mode}:{_api.MemLib.ReadByte(subObj + 0x70)}", Color.Red); + TickerText($"{_api.MemLib.ReadS32(subObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); + TickerText($"{_api.MemLib.ReadS32(subObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x50) / 65536.0:0.######}", Color.Red); + switch (mode) + { + case 0: + case 2: + case 4: + Xpos2 = _api.MemLib.ReadS32(0xFFAA22) - _api.MemLib.ReadS32(subObj + 0x24); + Ypos2 = _api.MemLib.ReadS32(0xFFAA26) - _api.MemLib.ReadS32(subObj + 0x28); + var dSml = Math.Abs(Xpos2); + var dBig = Math.Abs(Ypos2); + if (dBig < dSml) + { + dSml ^= dBig; + dBig ^= dSml; + dSml ^= dBig; + } + var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; + Xpos2 = (int)(Xpos2 * (256.0 / (rad + 1))) >> 20; + Ypos2 = (int)(Ypos2 * (256.0 / (rad + 1))) >> 20; + _api.GUILib.DrawLine(Xpos, Ypos, Xpos + Xpos2, Ypos + Ypos2, Color.Red); + break; + default: + break; + + } + } + } + else if ((type == 0xBA52E) && (subObj == _api.MemLib.ReadU24(curObj + 0x1D))) + { + DrawEccoOct(Xpos, Ypos, 32, (_api.MemLib.ReadByte(subObj + 0x70) == 0) ? Color.Blue : Color.Gray, 16); + var mode = _api.MemLib.ReadByte(curObj + 0x15); + TickerText($"{_api.MemLib.ReadByte(curObj + 0x14)}:{mode}:{_api.MemLib.ReadS16(curObj + 0x6E)}:{_api.MemLib.ReadByte(subObj + 0x70)}", Color.Red); + TickerText($"{_api.MemLib.ReadS32(subObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); + } + else if (type == 0xE0988) + { + DrawEccoOct(Xpos, Ypos, 48, Color.FromArgb(64, Color.Blue), 16); + } + if (HP > 2) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); + } + subObj = _api.MemLib.ReadU24(subObj + 5); + } + } + else if (type == 0xB7DF4) + { + Xpos = _api.MemLib.ReadS32(curObj + 0x24); + Ypos = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(Adelikat + 0x44), Color.Lime); - Adelikat = _api.MemLib.ReadU32(Adelikat + 4); + DrawEccoOct(Xpos, Ypos, 26, Color.PowderBlue); + DrawEccoOct(Xpos, Ypos, 26, Color.White); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec); } - Xpos = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x28); - Xpos -= _camX; - Ypos -= _camY; - } - else if (type == 0xE47EE) - { - uint Adelikat = curObj; - while (Adelikat != 0) + else if (type == 0xE47EE) { - Xpos = _api.MemLib.ReadS16(Adelikat + 0x1C); - Ypos = _api.MemLib.ReadS16(Adelikat + 0x20); + uint subObj = _api.MemLib.ReadU24(curObj + 5); + while (subObj != 0) + { + Xpos = _api.MemLib.ReadS32(subObj + 0x1C); + Ypos = _api.MemLib.ReadS32(subObj + 0x20); + Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, ((_api.MemLib.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.White); + DrawEccoOct(Xpos, Ypos, ((_api.MemLib.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.Yellow, 0); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + subObj = _api.MemLib.ReadU24(subObj + 5); + } + } + else if (type == 0xDBE64) // Medusa Boss + { + uint subObj = curObj; + uint next; + do + { + next = _api.MemLib.ReadU24(subObj + 5); + if (next != 0) subObj = next; + } while (next != 0); + Xpos = _api.MemLib.ReadS16(subObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(subObj + 0x34); + Ypos = _api.MemLib.ReadS16(subObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(subObj + 0x38); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + DrawEccoOct(Xpos, Ypos, 32, Color.Red); + DrawEccoOct(Xpos2, Ypos2, 32, Color.Red); + Xpos = _api.MemLib.ReadS32(curObj + 0x24); + Ypos = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, (_api.MemLib.ReadS16(Adelikat + 0x2C) >> 1) + 16, Color.Lime); - Adelikat = _api.MemLib.ReadU32(Adelikat + 4); + var octOff = (int)(Math.Sqrt(2) * 60) >> 1; + Point[] hemiOctPoints = + { + new Point(Xpos - 60, Ypos), + new Point(Xpos - octOff, Ypos - octOff), + new Point(Xpos, Ypos - 60), + new Point(Xpos + octOff, Ypos - octOff), + new Point(Xpos + 60, Ypos) + }; + _api.GUILib.DrawPolygon(hemiOctPoints, Color.Cyan, Color.FromArgb(0x3F, Color.Cyan)); + for (int l = 0; l < 4; l++) + { + _api.GUILib.DrawLine(hemiOctPoints[l].X, hemiOctPoints[l].Y, hemiOctPoints[l + 1].X, hemiOctPoints[l + 1].Y, Color.Cyan); + } + DrawBoxMWH(Xpos, Ypos + 12, 52, 12, Color.Cyan); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); } - Xpos = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x28); - Xpos -= _camX; - Ypos -= _camY; + else if (type == 0xDCEE0) // Globe Holder boss + { + uint subObj; + var mode = _api.MemLib.ReadByte(curObj + 0x15); + if (mode < 4) + { + subObj = _api.MemLib.ReadU24(curObj + 9); + while (subObj != 0) + { + Xmid = _api.MemLib.ReadS32(subObj + 0x24); + Ymid = _api.MemLib.ReadS32(subObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(subObj + 0x54) + _api.MemLib.ReadS32(subObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(subObj + 0x58) + _api.MemLib.ReadS32(subObj + 0x60)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawEccoOct(Xmid, Ymid, 12, Color.Orange); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + var next = _api.MemLib.ReadU24(subObj + 9); + if ((next == 0) && ((mode & 1) != 0)) + { + DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(subObj + 0x3C), Color.Orange); + } + subObj = _api.MemLib.ReadU24(subObj + 9); + } + subObj = _api.MemLib.ReadU24(curObj + 5); + while (subObj != 0) + { + Xmid = _api.MemLib.ReadS32(subObj + 0x24); + Ymid = _api.MemLib.ReadS32(subObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(subObj + 0x54) + _api.MemLib.ReadS32(subObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(subObj + 0x58) + _api.MemLib.ReadS32(subObj + 0x60)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawEccoOct(Xmid, Ymid, 12, Color.Orange); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + var next = _api.MemLib.ReadU24(subObj + 5); + if ((next == 0) && ((mode & 2) != 0)) + { + DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(subObj + 0x3C), Color.Orange); + } + subObj = _api.MemLib.ReadU24(subObj + 5); + } + } + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + int Xtmp = _api.MemLib.ReadS32(curObj + 0x2C); + int Ytmp = _api.MemLib.ReadS32(curObj + 0x30); + int Xtmp2 = _api.MemLib.ReadS32(curObj + 0x34); + int Ytmp2 = _api.MemLib.ReadS32(curObj + 0x38); + Xpos = (Xtmp >> 16) - _camX; Xpos2 = (Xtmp2 >> 16) - _camX; + Ypos = (Ytmp >> 16) - _camY; Ypos2 = (Ytmp2 >> 16) - _camY; + Xvec = ((_api.MemLib.ReadS32(curObj + 0x24) + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((_api.MemLib.ReadS32(curObj + 0x28) + +_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + if (mode < 7) + { + double overlap = 0; + DrawEccoOct(Xmid, Ymid, 0x5C, _api.MemLib.ReadByte(curObj + 0x7C) == 0 ? Color.Blue : Color.Gray); + DrawEccoOct(Xmid, Ymid, 0x5C, Color.Cyan, 0); + Xvec = (_api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)); + Yvec = (_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)); + subObj = _api.MemLib.ReadU24(curObj + 0x69); + if (subObj != 0) + { + Xpos = _api.MemLib.ReadS32(subObj + 0x2C); + Ypos = _api.MemLib.ReadS32(subObj + 0x30); + Xpos2 = _api.MemLib.ReadS32(subObj + 0x34); + Ypos2 = _api.MemLib.ReadS32(subObj + 0x38); + while ((Xtmp > Xpos) && (Xtmp2 < Xpos2) && (Ytmp > Ypos) && (Ytmp2 < Ypos2) && ((Xvec != 0) || (Yvec != 0))) + { + Xtmp += Xvec; Xtmp2 += Xvec; + Ytmp += Yvec; Ytmp2 += Yvec; + } + overlap = Math.Max(Math.Max(Xpos - Xtmp, Xtmp2 - Xpos2), Math.Max(Ypos - Ytmp, Ytmp2 - Ypos2)) / 65536.0; + Xpos >>= 16; Xpos2 >>= 16; + Ypos >>= 16; Ypos2 >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, 0); + } + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, (overlap >= 6) ? 63 : 0); + if (mode < 4) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x50) - _camY; + if ((mode & 1) == 0) DrawEccoOct(Xmid, Ymid - 0xAE, 32, Color.Orange); + if ((mode & 2) == 0) DrawEccoOct(Xmid, Ymid + 0xAE, 32, Color.Orange); + } + TickerText($"{mode}:{_api.MemLib.ReadByte(curObj + 0x7F)}:{_api.MemLib.ReadByte(curObj + 0x6D)}:{_api.MemLib.ReadByte(curObj + 0x7C)}", Color.Red); + } + else if (mode == 8) + { + DrawEccoOct(Xmid - 16, Ymid - 16, 12, Color.Red); + } + } + else if (type == 0xE1BA2) // Vortex Queen Boss + { + var vulnCount = _api.MemLib.ReadByte(curObj + 0x7F); + var state = _api.MemLib.ReadByte(curObj + 0x7C); + var stateCounter = _api.MemLib.ReadU16(curObj + 0x6E); + var mode = _api.MemLib.ReadU16(curObj + 0x64); + var modeCounter = _api.MemLib.ReadU16(curObj + 0x66); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x40); + Xvec = Xmid + _api.MemLib.ReadS32(curObj + 0x54); + Yvec = Ymid + _api.MemLib.ReadS32(curObj + 0x58); + Xvec >>= 16; Yvec >>= 16; + Xmid >>= 16; Ymid >>= 16; + Xvec -= _camX; Yvec -= _camY; + Xmid -= _camX; Ymid -= _camY; + if (mode < 5) + { + var octOff = (int)(80 * Math.Sqrt(2)) >> 1; + Point hexOff = Intersection(new Point(-80, 0), new Point(-octOff, -octOff), new Point(-80, -32), new Point(-octOff, -32)).Value; + Point[] roundedRect = { + new Point(Xmid - 80, Ymid), + new Point(Xmid + hexOff.X, Ymid - 32), + new Point(Xmid - hexOff.X, Ymid - 32), + new Point(Xmid + 80, Ymid), + new Point(Xmid - hexOff.X, Ymid + 32), + new Point(Xmid + hexOff.X, Ymid + 32) + }; + _api.GUILib.DrawPolygon(roundedRect, Color.Orange, Color.FromArgb(63, Color.Orange)); + } + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{state:X2}:{stateCounter}:{mode}:{modeCounter}:{_api.MemLib.ReadByte(curObj + 0x70) & 0xF}", Color.Red); + var subObj = _api.MemLib.ReadU24(curObj + 0x5); + var tongueMode = mode; + mode = _api.MemLib.ReadByte(subObj + 0x15); + modeCounter = _api.MemLib.ReadU16(subObj + 0x6E); + Xmid = _api.MemLib.ReadS32(subObj + 0x24); + Ymid = _api.MemLib.ReadS32(subObj + 0x40); + Xvec = (Xmid + _api.MemLib.ReadS32(subObj + 0x5C) >> 16) - _camX; + Yvec = (Ymid + _api.MemLib.ReadS32(subObj + 0x60) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Ymid -= 32; Yvec -= 32; + var levelHeight = _api.MemLib.ReadS16(0xFFA7AC) - _camY; + switch (mode) + { + case 0: + DrawBox(Xmid - 32, Ymid - ((state == 5) ? 0x60 : 0x70), Xmid + 32, Ymid - 16, Color.Red); + break; + case 2: + Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY; + _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); + break; + case 3: + modeCounter = _api.MemLib.ReadByte(subObj + 0x7C); + break; + case 5: + Point[] throatShape = + { + new Point(Xmid - 48, levelHeight), + new Point(Xmid - 48, Ymid + 60), + new Point(Xmid - 16, Ymid + 20), + new Point(Xmid + 16, Ymid + 20), + new Point(Xmid + 48, Ymid + 60), + new Point(Xmid + 48, levelHeight) + }; + _api.GUILib.DrawPolygon(throatShape, Color.Red, Color.FromArgb(63, Color.Red)); + DrawEccoOct(Xmid, Ymid, 24, Color.Red); + DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); + break; + case 6: + if ((state != 7) && (vulnCount == 0) && (tongueMode != 7)) + { + DrawEccoOct(Xmid, Ymid + 16, 64, Color.Blue); + } + if (tongueMode == 7) + { + uint subObj2 = _api.MemLib.ReadU24(0xFFCFCD); + while (subObj2 != 0) + { + if (_api.MemLib.ReadU16(subObj2 + 0x10) == 0xFF) + { + Xpos = _api.MemLib.ReadS16(subObj2 + 0x24) - _camX; + Ypos = _api.MemLib.ReadS16(subObj2 + 0x28) - _camY; + Xpos2 = ((_api.MemLib.ReadS32(subObj2 + 0x24) + _api.MemLib.ReadS32(subObj2 + 0x54)) >> 16) - _camX; + Ypos2 = ((_api.MemLib.ReadS32(subObj2 + 0x28) + _api.MemLib.ReadS32(subObj2 + 0x58)) >> 16) - _camY; + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + } + subObj2 = _api.MemLib.ReadU24(subObj2 + 1); + } + } + Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY; + _api.GUILib.DrawLine(Xmid - 48, Ypos - 94, Xmid + 48, Ypos - 94, Color.Orange); + _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); + break; + default: + break; + } + if ((mode < 7) || ((mode == 7) && (_api.MemLib.ReadU24(0xFFCFC9) != 0))) + { + if (_api.MemLib.ReadByte(subObj + 0x70) == 0) + { + DrawEccoOct(Xmid, Ymid, 32, Color.Red); + DrawBox(Xmid - 48, Ymid + 32, Xmid + 48, levelHeight, Color.Red); + } + Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY - 94; + _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); + } + if (_api.MemLib.ReadS32(subObj + 0xC) == 0xE17B4) + { + Point[] shapePoints = + { + new Point(Xmid - 48, levelHeight), + new Point(Xmid - 48, Ymid + 60), + new Point(Xmid - 16, Ymid + 20), + new Point(Xmid + 16, Ymid + 20), + new Point(Xmid + 48, Ymid + 60), + new Point(Xmid + 48, levelHeight) + }; + _api.GUILib.DrawPolygon(shapePoints, Color.Red, Color.FromArgb(63, Color.Red)); + DrawEccoOct(Xmid, Ymid, 24, Color.Red); + DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); + } + Ypos = (_api.MemLib.ReadS16(subObj + 0x50) - _camY) - 264; + DrawBoxMWH(160 + _left, Ypos, 320, 12, (32 < stateCounter) && (stateCounter < 160) ? Color.Brown : Color.Gray); + if ((32 < stateCounter) && (stateCounter < 160)) + { + DrawBoxMWH(_left + 160, Ypos, 320, 12, Color.White, 0); + } + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{mode:X2}:{modeCounter}:{HP}:{vulnCount}", Color.Red); + HP = 0; + } + else if (type == 0xA5BD2) // Telekinetic future dolphins + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); + DrawEccoOct(Xmid, Ymid, 4, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0x9F5B0) || (type == 0x9F4DC) || (type == 0x9F6A0)) // Falling rock, breaks barriers + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + if (type == 0x9F6A0) + { + int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); + } + TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); + } + else if (type == 0xA3B18) + { + Xpos = _api.MemLib.ReadS32(curObj + 0x24); + Ypos = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Yellow); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + } + else if (type == 0xA4018) + { + Xpos = _api.MemLib.ReadS32(curObj + 0x24); + Ypos = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; + Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Gray); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + } + else if (type == 0xA091E) // Blue Whale + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xpos = Xmid; Ypos = Ymid; + Ymid -= 64; Yvec -= 64; + DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x50, Color.Red, 31); + DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x40, Color.Red, 31); + DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x30, Color.Red, 31); + DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x20, Color.Red, 31); + DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x10, Color.Red, 31); + if (_api.MemLib.ReadByte(curObj + 0x7F) == 0) + { + Xpos += (_api.MemLib.ReadS16(curObj + 0x6E) == 0) ? -278 : 162; + Ypos += 44 - _api.MemLib.ReadS16(curObj + 0x48); + DrawEccoOct(Xpos, Ypos, 32, Color.Blue); + } + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + + } + else if (type == 0xE66D8) //Vortex Larva + { + uint subObj = _api.MemLib.ReadU24(curObj + 5); + while (subObj != 0) + { + Xpos = _api.MemLib.ReadS16(subObj + 0x1C); + Ypos = _api.MemLib.ReadS16(subObj + 0x20); + Xpos2 = _api.MemLib.ReadS16(subObj + 0x24); + Ypos2 = _api.MemLib.ReadS16(subObj + 0x28); + Xpos -= _camX; Ypos -= _camY; + Xpos2 -= _camX; Ypos2 -= _camY; + DrawEccoOct(Xpos, Ypos, 30, Color.White, 32); + DrawEccoOct(Xpos, Ypos, 30, Color.Yellow, 0); + DrawEccoOct(Xpos2, Ypos2, 30, Color.White, 32); + DrawEccoOct(Xpos2, Ypos2, 30, Color.Yellow, 0); + subObj = _api.MemLib.ReadU24(subObj + 5); + } + Xpos = _api.MemLib.ReadS32(curObj + 0x24); + Ypos = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x72) - _camX; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x76) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; Ypos -= _camY; + DrawEccoOct(Xpos, Ypos, 0xB0, Color.Yellow); + DrawEccoOct(Xpos, Ypos, 0xB0, Color.Red, 0); + DrawEccoOct(Xpos, Ypos, 0x70, Color.Red); + DrawEccoOct(Xpos, Ypos, 0x38, Color.White); + DrawEccoOct(Xpos, Ypos, 0x38, Color.Red, 0); + DrawEccoOct(Xpos, Ypos, 48, Color.Blue, ((_api.MemLib.ReadByte(curObj + 0x7B) > 2) && (_api.MemLib.ReadByte(curObj + 0x14) != 0)) ? 63 : 0); + DrawEccoOct(Xpos2, Ypos2, 32, Color.Orange); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + TickerText($"{_api.MemLib.ReadByte(curObj + 0x14):X2}:{_api.MemLib.ReadByte(curObj + 0x7B):X2}:{_api.MemLib.ReadS16(curObj + 0x6E):D2}", Color.Red); + TickerText($"{ _api.MemLib.ReadByte(curObj + 0x7C):X2}:{_api.MemLib.ReadS16(curObj + 0x18):D3}", Color.Red); + TickerText($"{(_api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C))/65536.0:0.######}:{(_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) / 65536.0:0.######}", Color.Red); + + } + else if (type == 0x9CE3A) //Remnant Stars + { + flags = _api.MemLib.ReadU16(curObj + 0x10); + uint subObj = _api.MemLib.ReadU24(curObj + 0x5); + uint anim = _api.MemLib.ReadU16(curObj + 0x6C); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + if ((anim <= 7) && (subObj == 0xFFA9D4)) + { + DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); + PutText($"{((7 - anim) * 4) - ((_api.MemLib.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Blue, Color.Red); + + } + } + else if (type == 0xA997C) // Vortex Soldier + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = (Xmid + _api.MemLib.ReadS32(curObj + 0x54) >> 16) - _camX; + Yvec = (Ymid + _api.MemLib.ReadS32(curObj + 0x58) >> 16) - _camY; + Xvec += _api.MemLib.ReadS16(curObj + 0x64); + Yvec += _api.MemLib.ReadS16(curObj + 0x66); + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + if (_api.MemLib.ReadByte(curObj + 0x7A) == 0) + { + DrawRectRhombusIntersection(new Point(Xmid, Ymid + 6), new Point(Xmid, Ymid), 50, 44, 64, Color.Red); + } + DrawRectRhombusIntersection(new Point(Xmid, Ymid - 25), new Point(Xmid, Ymid), 38, 47, 64, Color.Red); + DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue, 16); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xA6C4A) || (type == 0xC43D4)) // Barrier Glyphs + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + var subType = _api.MemLib.ReadByte(curObj + 0x13); + if ((_api.MemLib.ReadU8(curObj + 0x7A) == 0) && (_api.MemLib.ReadU8(0xFFA7B5) != 0) + && ((type != 0xA6C4A) || (subType == 0x14) || (subType == 0x97))) + { + DrawEccoOct(Xmid, Ymid, 70, Color.Red); + } + DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue); + DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.PowderBlue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xB4F46) || (type == 0xB4E1C) || (type == 0xB4C18) || (type == 0xB4ACC) || (type == 0xB4B72)) // Guiding Orca/Dolphin + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + int Xdst = _api.MemLib.ReadS16(curObj + 0x64); + Xdst <<= 7; + Xdst = Xdst + 0x40 - _camX; + int Ydst = _api.MemLib.ReadS16(curObj + 0x66); + Ydst <<= 7; + Ydst = Ydst + 0x40 - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + _api.GUILib.DrawLine(Xmid, Ymid, Xdst, Ydst, Color.Orange); + DrawBoxMWH(Xdst, Ydst, 64, 64, Color.Orange); + TickerText($"{_api.MemLib.ReadS16(curObj + 0x24)}:{_api.MemLib.ReadS16(curObj + 0x28)}:{_api.MemLib.ReadByte(curObj + 0x7D)}:{_api.MemLib.ReadByte(curObj + 0x7A)}", Color.Lime); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x72) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x76) / 65536.0:0.######}", Color.Lime); + } + else if (type == 0xB5938) // Lost Orca + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + //DrawBoxMWH(Xmid, Ymid, 64, 32, Color.Lime); + if (_api.MemLib.ReadU16(curObj + 0x6E) == 0) + { + if (_api.MemLib.ReadByte(curObj + 0x7D) == 0) + { + DrawBox(Xmid + 8, Ymid - 32, Xmid + 64, Ymid + 32, Color.Red); + } + else + { + DrawBox(Xmid - 64, Ymid - 32, Xmid - 8, Ymid + 32, Color.Red); + } + } + _api.GUILib.DrawLine(Xpos - 80, Ymid, Xpos + 80, Ymid, Color.Green); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xB552A) || (type == 0xB5C42) || (type == 0xB5AFE)) // Following Orca, Returning Orca, & Idling Orca + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xB624A) // Orca Mother + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + int height = _api.MemLib.ReadS16(curObj + 0x48) + 32; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 80, 32, Color.Red, 31); + DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + if (_api.MemLib.ReadS32(0xFFAB7E) != 0) + { + DrawEccoOct(Xmid, Ymid, 0x50, Color.Red, 31); + } + } + else if (type == 0xC047E) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + var width = 2; + var height = 2; + if (_api.MemLib.ReadByte(curObj + 0x15) == 0) + { + width = _api.MemLib.ReadS16(curObj + 0x44); + height = _api.MemLib.ReadS16(curObj + 0x48); + } + DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); + } + else if (type == 0xC056E) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + var width = _api.MemLib.ReadS16(curObj + 0x44); + var height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); + } + else if (type == 0xC4208) // Broken Glyph Base + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + var width = _api.MemLib.ReadS16(curObj + 0x44); + var height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.PowderBlue); + if (_api.MemLib.ReadByte(curObj + 0x15) == 0) + { + DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 80, 80, 120, Color.Orange); + } + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xAC242) // Broken Glyph Top repairing + { + uint subObj = _api.MemLib.ReadU24(curObj + 0x5); + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xpos = _api.MemLib.ReadS16(subObj + 0x24) - _camX; + Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; + var width = _api.MemLib.ReadS16(curObj + 0x44); + var height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Gray); + Point[] rhombPoints = + { + new Point(Xpos - 3, Ypos), + new Point(Xpos, Ypos - 3), + new Point(Xpos + 3, Ypos), + new Point(Xpos, Ypos + 3) + }; + _api.GUILib.DrawPolygon(rhombPoints, Color.Orange, Color.FromArgb(63, Color.Orange)); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + } + else if (type == 0xBE9C8) // Broken Glyph Top free + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xD9C0E) || (type == 0xDA9EA)) + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBoxMWH(Xmid, Ymid, 0xA0, 0x70, Color.Red); + } + else if ((type == 0xBF204) || (type == 0xDA2C0)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xAF9CC) // Mirror Dolphin + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX + (_api.MemLib.ReadByte(curObj + 0x15) == 0 ? 27 : -27); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + var width = _api.MemLib.ReadS16(curObj + 0x44); + var height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue, 31); + if (_api.MemLib.ReadByte(curObj + 0x13) != 0xAC) + { + DrawBoxMWH(Xmid, Ymid, 96, 96, Color.Orange); + } + _api.GUILib.DrawLine(Xpos, 0, Xpos, 448, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xAF43E) // Vortex Lightning Trap + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + if (_api.MemLib.ReadByte(curObj + 0x15) != 0) + { + if (_api.MemLib.ReadS16(0xFFAA12) != 0) + { + Ymid -= 8; + } + DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Red); + PutText(_api.MemLib.ReadByte(curObj + 0x15).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); + } + else + { + DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Gray); + PutText(_api.MemLib.ReadByte(curObj + 0x7F).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); + } + } + else if (type == 0xA6E24) // Barrier Glyph Forcefield + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = _api.MemLib.ReadS32(0xFFAA1A) - Xmid; + Yvec = _api.MemLib.ReadS32(0xFFAA1E) - Ymid; + var div = Math.Abs(Xvec) + Math.Abs(Yvec); + Xvec /= div; Yvec /= div; + Xvec += Xmid; Yvec += Ymid; + Xmid >>= 16; Ymid >>= 16; + Xvec >>= 16; Yvec >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xvec -= _camX; Yvec -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xC4A44) || (type == 0xAA32C)) // Pulsar power-up and Vortex bullet-spawner + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue, 16); + } + else if (type == 0xC2F00) // Sky bubbles + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + var mode = _api.MemLib.ReadByte(curObj + 0x15); + switch (mode) + { + case 0: + DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 70, 70, 105, Color.Gray); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + break; + case 1: + DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 70, 70, 105, Color.Red); + break; + case 2: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); + break; + default: + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Gray); + break; + } + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0x9FA7E) //Air refiller/drainer + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Lime)); + } + else if (type == 0xBFC14) //Pushable fish + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Orange); + + } + else if ((type == 0xBE97C) //Slowing Kelp //Default Bounds nose-responsive + || (type == 0xACDAE)) //Metasphere + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xACB42) // Turtle + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + var mode = _api.MemLib.ReadByte(curObj + 0x15); + switch (mode) + { + case 0: + case 1: + case 2: + case 3: + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x4C)) >> 16) - _camX; + break; + case 4: + case 5: + case 6: + case 7: + Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x4C)) >> 16) - _camX; + break; + default: + Xvec = (Xmid >> 16) - _camX; + break; + } + Yvec = Ymid; + Xmid >>= 16; Xmid -= _camX; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); + TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xACA7E) // Retracting Turtle + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + (_api.MemLib.ReadS32(curObj + 0x4C) >> 1)) >> 16) - _camX; + Yvec = ((Ymid + (_api.MemLib.ReadS32(curObj + 0x50) >> 1)) >> 16) - _camY; + Xmid >>= 16; Xmid -= _camX; + Ymid >>= 16; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); + TickerText($"{(_api.MemLib.ReadS32(curObj + 0x4C) >> 1) / 65536.0:0.######}:{(_api.MemLib.ReadS32(curObj + 0x50) >> 1) / 65536.0:0.######}", Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xB5134) || (type == 0xA7E0C) //Default Bounds sonar-responsive + || (type == 0xAF868) || (type == 0xAF960) || (type == 0xD8E5C) || (type == 0xAA5C6)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if ((type == 0xACCB4) || (type == 0xACD7E) //Default Baunds non-responsive + || (type == 0xD8D96) || (type == 0xA955E) || (type == 0xA92E4) || (type == 0xC05DC) + || (type == 0xC2684)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Gray); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0x9DE86) // Star Wreath + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xpos = _api.MemLib.ReadS32(curObj + 0x1C); + Ypos = _api.MemLib.ReadS32(curObj + 0x20); + Xpos2 = ((Xpos + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Ypos2 = ((Ypos + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; Ypos -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + DrawBoxMWH(Xpos, Ypos, 1, 1, (_api.MemLib.ReadByte(curObj + 0x7F) == 0) ? Color.Blue : Color.Black, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + if (_api.MemLib.ReadByte(curObj + 0x12) % 7 == 0) + { + TickerText($"{_api.MemLib.ReadS32(curObj + 0x5C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x60) / 65536.0:0.######}:{_api.MemLib.ReadByte(curObj + 0x7F)}", Color.Lime); + } + } + else if ((type == 0x9D774) || (type == 0x9DA26)) // Fish + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 0x14, 0x14, Color.Lime); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xAD87C) // Enemy dolphins in metamorph levels + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(_api.MemLib.ReadS16(curObj + 0x1C) - _camX, _api.MemLib.ReadS16(curObj + 0x20) - _camY, 1024, 1024, Color.Orange, 0); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC6128) // Drone attacking dolphin + { + Xmid = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x50) - _camY; + DrawEccoOct(Xmid, Ymid, 360, Color.Red, 0); + } + else if (type == 0xC605A) // Drone attacking dolphin sonar + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camY; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBox(Xmid, Ymid - 1, Xmid + 32, Ymid + 1, Color.Orange); + } + else if (type == 0xB1BE0) // Globe + { + int mode = _api.MemLib.ReadS8(curObj + 0x15); + if (mode == 1) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); + _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xB1A10) // Approaching globes + { + Xmid = _api.MemLib.ReadS16(0xFFAA1A) - _camX; + Ymid = _api.MemLib.ReadS16(0xFFAA1E) - _camY; + DrawEccoOct(Xmid - 56, Ymid, 8, Color.Orange); + DrawEccoOct(Xmid + 56, Ymid, 8, Color.Orange); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = _api.MemLib.ReadS32(curObj + 0x4C); + Ypos = _api.MemLib.ReadS32(curObj + 0x50); + Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos2 = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Ypos2 = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xpos >>= 16; Ypos >>= 16; + Xpos -= _camX; Ypos -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + } + else if (type == 0xB1920) // Orbiting globes + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x50) - _camY; + Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC28A0) // Control point in Four Islands/Dolphin that gives Rock-breaking song + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, _api.MemLib.ReadByte(curObj + 0x15) == 0 ? Color.Orange : Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + // Crystal Springs merging glyphs + else if (type == 0xC651E) // Bound glyph + { + Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + DrawEccoRhomb(Xpos, Ypos, 4 << 4, Color.Orange); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC67E4) // Freed glyph + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC6970) // Pulled glyph + { + uint subObj = _api.MemLib.ReadU24(curObj + 5); + Xvec = _api.MemLib.ReadS32(subObj + 0x54); + Yvec = _api.MemLib.ReadS32(subObj + 0x58); + for (i = 1; i < _api.MemLib.ReadByte(curObj + 0x7F); i++) + { + Xvec ^= Yvec; + Yvec ^= Xvec; + Xvec ^= Yvec; + Xvec = 0 - Xvec; + } + Xpos = (Xvec + _api.MemLib.ReadS32(subObj + 0x1C) >> 16) - _camX; + Ypos = (Yvec + _api.MemLib.ReadS32(subObj + 0x20) >> 16) - _camY; + DrawEccoRhomb(Xpos, Ypos, 3, Color.Orange); + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); + } + else if (type == 0xC6BA8) // Delivery Point + { + Xvec = _api.MemLib.ReadS32(curObj + 0x54); + Yvec = _api.MemLib.ReadS32(curObj + 0x58); + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + for (i = 0; i < 4; i++) + { + Xpos = (Xvec + _api.MemLib.ReadS32(curObj + 0x1C) >> 16) - _camX; + Ypos = (Yvec + _api.MemLib.ReadS32(curObj + 0x20) >> 16) - _camY; + _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + Xvec ^= Yvec; + Yvec ^= Xvec; + Xvec ^= Yvec; + Xvec = 0 - Xvec; + } + } + else if (type == 0xC6A6C) // Delivered glyph + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC6F82) // Full delivery point + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawEccoOct(Xmid, Ymid, 3, Color.Orange); + } + else if (type == 0xC6A9E) // Merging glyph + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xC7052) { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS16(curObj + 0x24); + Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + uint dropSpeed = _api.MemLib.ReadU8(curObj + 0x16); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ymid + (int)(dropSpeed), Color.Orange); + } + else if ((type == 0xD8B7C) || (type == 0xD89EA) || (type == 0x9E3AA) || (type == 0x9E5A8) // GFX particles don't need displayed. + || (type == 0x9B5D8) || (type == 0x9E2A6) || (type == 0xACD1E) || (type == 0xD9678) + || (type == 0xD9A3C) || (type == 0xD9240) || (type == 0x9E1DE) || (type == 0xDF86A) + || (type == 0xB159A) || (type == 0xDA898) || (type == 0xDA720) || (type == 0xD9FDC) + || (type == 0xC0D4E) || (type == 0xC0D38) || (type == 0xDCDAC) || (type == 0xC0B42) + || (type == 0xE3CD2) || (type == 0xE385E) || (type == 0xC20E8) || (type == 0xC22A6) + || (type == 0xC31B4) || (type == 0xA9EF0) || (type == 0xA9D90) || (type == 0xC6304) + || (type == 0xC26E4) || (type == 0xAEE68) || (type == 0xD9B2A) || (type == 0xD95AE) + || (type == 0)) + { + // This space intentionally left blank + } + else if ((type == 0xC152C) || (type == 0xA75E8) //Objects with default bounds confirmed + || (type == 0x9D076) || (type == 0xA7092) || (type == 0xC02EA) || (type == 0xA5378) + || (type == 0xACA7E) || (type == 0x9D28C) || (type == 0xA2D42) || (type == 0xA975E) + || (type == 0xBE9C8) || (type == 0xBFDA4) || (type == 0xAC736) || (type == 0xB716E) + || (type == 0xB1BE0) || (type == 0xB1A10) || (type == 0x9E546) || (type == 0xC2CB8) + || (type == 0xA0F04) || (type == 0xA6ACA) || (type == 0xA35A6) || (type == 0xAA12E) + || (type == 0xC651E) || (type == 0x9CC06) || (type == 0xA9202) || (type == 0xA6FDE) + || (type == 0xA6F62) || (type == 0xA745C) || (type == 0xC3EF0) || (type == 0xC3F90) + || (type == 0xC3FFC) || (type == 0xC3DB8) || (type == 0xAC766) || (type == 0xC5F66) + || (type == 0xA306E) || (type == 0xB0C7E) || (type == 0xB17F2) || (type == 0xB0CDC) + || (type == 0xC2106) || (type == 0xC208C) || (type == 0xC1EBA) || (type == 0xC251C) + || (type == 0xC32C8) || (type == 0xAB5E6) || (type == 0xAC796) || (type == 0xAC9F2) + || (type == 0xA538A)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(255, 0, 127)); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); + if (type != 0xA975E) + { + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + if (HP > 2) + { + PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); + } + } + else // Default bounds + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + PutText(type.ToString("X5"), Xmid, Ymid + 8, 1, 9, -1, -1, Color.Blue, Color.Red); + } + break; } - else if ((type == 0x9F5B0) || (type == 0xA3B18)) - { - Xpos = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x28); - Xpos -= _camX; - Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Lime); - } - else if (type == 0xDCEE0) - { - Xpos = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x28); - Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, 0x5C, Color.Lime); - } - else - { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS16(curObj + 0x24); - Ymid = _api.MemLib.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - if ((type == 0xA6C4A) || (type == 0xC43D4)) DrawEccoOct(Xmid, Ymid, 70, Color.Lime); - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - } - break; - } case Modes.Ecco1: type = _api.MemLib.ReadU32(curObj + 0x6); Xpos = _api.MemLib.ReadS16(curObj + 0x17); @@ -544,26 +2442,51 @@ namespace BizHawk.Client.EmuHawk Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - break; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + PutText(type.ToString("X8"), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); + break; } - Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(0, Ymid-5), 424), Color.Blue); - Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(2, Ymid-3), 426), Color.Blue); - Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(0, Xmid-16), 605), Math.Min(Math.Max(2, Ymid-3), 426), Color.Blue); - Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(2, Xmid-14), 607), Math.Min(Math.Max(0, Ymid-5), 424), Color.Blue); - Print_Text(type.ToString("X8"), 8, Math.Min(Math.Max(1, Xmid-15), 606), Math.Min(Math.Max(1, Ymid-4), 425), Color.Red); curObj = _api.MemLib.ReadU24(curObj+1); } //events curObj = _api.MemLib.ReadU24(0xFFCFB5); while (curObj != 0) { - uint type = _api.MemLib.ReadU32(curObj + 0xC); - if ((type == 0xA44EE) || (type == 0xD120C)) + type = _api.MemLib.ReadU32(curObj + 0xC); + if ((type == 0) // Null object + || (type == 0x9C1FA) || (type == 0x9C6D0) // Skytubes BG Image manager + || (type == 0x9ED72) || (type == 0xA57F2) // And Miscellaneous GFX particles + || (type == 0xC3A42) || (type == 0xB33D8) // And Cutscene controller + || (type == 0xB308A) || (type == 0xA1676) || (type == 0xB6822) || (type == 0xD12E2)) { } + else if ((type == 0xA44EE) || (type == 0xD120C)) { Xmid = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; Ymid = _api.MemLib.ReadS16(curObj + 0x20) - _camY; - DrawEccoOct(Xmid, Ymid, 0x20, Color.Cyan); + DrawEccoOct(Xmid, Ymid, 0x20, Color.Red); + } + else if (type == 0x9F0D0) // Water Current + { + int Xvec = _api.MemLib.ReadS32(curObj + 0x54); + int Yvec = _api.MemLib.ReadS32(curObj + 0x58); + if ((Xvec != 0) || (Yvec != 0)) + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xvec += Xmid; Yvec += Ymid; + Xmid >>= 16; Ymid >>= 16; + Xvec >>= 16; Yvec >>= 16; + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + Xvec -= _camX; Yvec -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Red)); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } } else if (type == 0xDEF94) { @@ -571,9 +2494,179 @@ namespace BizHawk.Client.EmuHawk Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; DrawEccoOct(Xmid, Ymid, 0x18, Color.Cyan); } - else + else if (type == 0xA6584) // Eagle { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawEccoOct(Xmid, Ymid, 0x10, Color.Red); + } + else if ((type == 0x9BA8A) // Autoscroller controller + || (type == 0xE27D4) || (type == 0xE270E) || (type == 0xE26C2)) + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + var Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + var Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0x9B948) // Autoscroller waypoint + { + Xmid = _api.MemLib.ReadS32(curObj + 0x24); + Ymid = _api.MemLib.ReadS32(curObj + 0x28); + var Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; + var Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; + DrawBoxMWH(Xmid, Ymid, 8, 8, Color.Orange); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + } + else if (type == 0xA5448) // Bomb spawner + { + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + PutText($"{_api.MemLib.ReadU16(curObj + 0x6E)}", Xmid, Ymid, 1, 1, -1, -1, Color.White, Color.Blue); + } + else if ((type == 0xA529C) || (type == 0xA5236) || (type == 0xA51E6)) // Explosion + { + uint subObj = _api.MemLib.ReadU24(curObj + 5); + if (subObj != 0) + { + Xpos = _api.MemLib.ReadS16(subObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; + int Width = _api.MemLib.ReadS16(subObj + 0x24) - Xpos - _camX; + DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); + } + subObj = _api.MemLib.ReadU24(curObj + 9); + if (subObj != 0) + { + Xpos = _api.MemLib.ReadS16(subObj + 0x1C) - _camX; + Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; + int Width = _api.MemLib.ReadS16(subObj + 0x24) - Xpos - _camX; + DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); + } + } + else if (type == 0x9B5D8) + { + var subtype = _api.MemLib.ReadByte(curObj + 0x13); + int width = 0; + int height = 0; + switch (subtype) + { + case 48: + case 49: + case 126: + case 145: + case 146: + case 213: + PutText($"{type:X5}:{subtype}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); + PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); + break; + case 59: + case 87: + case 181: + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + width = _api.MemLib.ReadS16(curObj + 0x44); + height = _api.MemLib.ReadS16(curObj + 0x48); + DrawEccoOct(Xmid, Ymid, (width + height) >> 1, Color.Lime); + break; + case 71: + case 72: + case 158: + case 159: + case 165: + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); + break; + case 82: + case 83: + case 84: + case 85: + case 86: + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + width = _api.MemLib.ReadS16(curObj + 0x44); + height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Red); + break; + case 210: + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + width = _api.MemLib.ReadS16(curObj + 0x44); + height = _api.MemLib.ReadS16(curObj + 0x48); + DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue); + break; + case 107: + Xmid = (_api.MemLib.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; + Ymid = (_api.MemLib.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; + Xpos = (_api.MemLib.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; + Ypos = (_api.MemLib.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; + DrawBoxMWH(Xmid, Ymid, 64, 64, Color.Orange, 0); + DrawBoxMWH(Xpos, Ypos, 64, 64, Color.Orange, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + break; + case 110: //Gravity conrol points + case 179: + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63,_api.MemLib.ReadByte(curObj + 0x15) == 0 ? Color.Gray : Color.Red)); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); + int dir = _api.MemLib.ReadS8(curObj + 0x71) & 7; + int[] xtable = { 7, 4, -3, -10, -14, -11, -3, 4}; + int[] ytable = { 11, 4, 7, 4, -3, -11, -14, -11}; + Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; + Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawImage(".\\dll\\gravitometer_bg.png", Xmid - 15, Ymid - 15); + _api.GUILib.DrawImage(".\\dll\\gravitometer_fg.png", Xmid + xtable[dir], Ymid + ytable[dir]); + break; + case 176: + Xmid = (_api.MemLib.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; + Ymid = (_api.MemLib.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; + Xpos = (_api.MemLib.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; + Ypos = (_api.MemLib.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; + DrawEccoOct(Xmid, Ymid, 32, Color.Orange, 0); + DrawEccoOct(Xpos, Ypos, 32, Color.Orange, 0); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + break; + case 194: // Kill plane + Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; + Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Black, 127); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); + break; + default: + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); + Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); + Ypos = _api.MemLib.ReadS16(curObj + 0x30); + Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xmid = _api.MemLib.ReadS16(curObj + 0x24); + Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos -= _camX; Xpos2 -= _camX; + Ypos -= _camY; Ypos2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); + PutText($"{type:X5}:{subtype}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); + PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); + break; + } + } + else + { + Xpos = _api.MemLib.ReadS16(curObj + 0x2C); Xpos2= _api.MemLib.ReadS16(curObj + 0x34); Ypos = _api.MemLib.ReadS16(curObj + 0x30); Ypos2= _api.MemLib.ReadS16(curObj + 0x38); @@ -582,93 +2675,117 @@ namespace BizHawk.Client.EmuHawk Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); - } - PutText(type.ToString("X8"), Xmid, Ymid, 1, 1, 0, 0, Color.White, Color.Blue); - PutText(curObj.ToString("X8"), Xmid, Ymid, 1, 9, 0, 0, Color.White, Color.Blue); - curObj = _api.MemLib.ReadU24(curObj+1); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); + PutText($"{type:X5}:{_api.MemLib.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); + PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); + } + curObj = _api.MemLib.ReadU24(curObj+1); } - //Ecco body - Xpos = _api.MemLib.ReadS16(0xFFAA22); - Ypos = _api.MemLib.ReadS16(0xFFAA26); - Xpos2 = _api.MemLib.ReadS16(0xFFAA2A); - Ypos2 = _api.MemLib.ReadS16(0xFFAA2E); - Xmid = _api.MemLib.ReadS16(0xFFAA1A); - Ymid = _api.MemLib.ReadS16(0xFFAA1E); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - X = Xpos; - X2 = Xpos2; - Y = Ypos; - Y2 = Ypos2; - int X3 = (Xmid + (ushort) Xpos) >> 1; - int X4 = (Xmid + (ushort) Xpos2) >> 1; - int Y3 = (Ymid + (ushort) Ypos) >> 1; - int Y4 = (Ymid + (ushort) Ypos2) >> 1; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Magenta); - DrawBoxMWH(X, Y, 1, 1, Color.Magenta); - DrawBoxMWH(X2, Y2, 1, 1, Color.Magenta); - DrawBoxMWH(X3, Y3, 1, 1, Color.Magenta); - DrawBoxMWH(X4, Y4, 1, 1, Color.Magenta); - _api.GUILib.DrawPixel(Xmid, Ymid, Color.Blue); - _api.GUILib.DrawPixel(X, Y, Color.Blue); - _api.GUILib.DrawPixel(X2, Y2, Color.Blue); - _api.GUILib.DrawPixel(X3, Y3, Color.Blue); - _api.GUILib.DrawPixel(X4, Y4, Color.Blue); - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); //Ecco head Xpos = _api.MemLib.ReadS16(0xFFA8F8); Xpos2 = _api.MemLib.ReadS16(0xFFA900); Ypos = _api.MemLib.ReadS16(0xFFA8FC); Ypos2 = _api.MemLib.ReadS16(0xFFA904); + Xmid = _api.MemLib.ReadS16(0xFFA8F0); + Ymid = _api.MemLib.ReadS16(0xFFA8F4); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); //Ecco tail Xpos = _api.MemLib.ReadS16(0xFFA978); Xpos2 = _api.MemLib.ReadS16(0xFFA980); Ypos = _api.MemLib.ReadS16(0xFFA97C); Ypos2 = _api.MemLib.ReadS16(0xFFA984); + Xmid = _api.MemLib.ReadS16(0xFFA970); + Ymid = _api.MemLib.ReadS16(0xFFA974); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; - _api.GUILib.DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.White); + Xmid -= _camX; Ymid -= _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); + //Ecco body + Xpos = _api.MemLib.ReadS32(0xFFAA22); + Ypos = _api.MemLib.ReadS32(0xFFAA26); + Xpos2 = _api.MemLib.ReadS32(0xFFAA2A); + Ypos2 = _api.MemLib.ReadS32(0xFFAA2E); + Xmid = _api.MemLib.ReadS16(0xFFAA1A); + Ymid = _api.MemLib.ReadS16(0xFFAA1E); + int Xvel = _api.MemLib.ReadS32(0xFFAA36); + if (_api.MemLib.ReadU32(0xFFA9D6) > 7) Xvel += _api.MemLib.ReadS32(0xFFA9D6); + if (_api.MemLib.ReadU32(0xFFAA3E) > 7) Xvel += _api.MemLib.ReadS32(0xFFAA3E); + int Yvel = _api.MemLib.ReadS32(0xFFAA3A); + if (_api.MemLib.ReadU32(0xFFA9DA) > 7) Yvel += _api.MemLib.ReadS32(0xFFA9DA); + if (_api.MemLib.ReadU32(0xFFAA42) > 7) Yvel += _api.MemLib.ReadS32(0xFFAA42); + int XV = ((Xpos + Xvel) >> 16) - _camX; + int YV = ((Ypos + Yvel) >> 16) - _camY; + int XV2 = ((Xpos2 + Xvel) >> 16) - _camX; + int YV2 = ((Ypos2 + Yvel) >> 16) - _camY; + X = Xpos >> 16; + X2 = Xpos2 >> 16; + Y = Ypos >> 16; + Y2 = Ypos2 >> 16; + X -= _camX; X2 -= _camX; + Y -= _camY; Y2 -= _camY; + Xmid -= _camX; Ymid -= _camY; + int X3 = (Xmid + X) >> 1; + int X4 = (Xmid + X2) >> 1; + int Y3 = (Ymid + Y) >> 1; + int Y4 = (Ymid + Y2) >> 1; + _api.GUILib.DrawLine(X, Y, Xmid, Ymid, Color.Green); + _api.GUILib.DrawLine(Xmid, Ymid, X2, Y2, Color.Green); + DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Red); + DrawBoxMWH(X, Y, 1, 1, Color.Lime); + DrawBoxMWH(X2, Y2, 1, 1, Color.Blue); + DrawBoxMWH(X3, Y3, 1, 1, Color.Yellow); + DrawBoxMWH(X4, Y4, 1, 1, Color.Yellow); + _api.GUILib.DrawLine(X, Y, XV, YV, Color.Orange); + _api.GUILib.DrawLine(X2, Y2, XV2, YV2, Color.Orange); // sonar if (_api.MemLib.ReadU8(0xFFAB77) != 0) { - Xmid = _api.MemLib.ReadS16(0xFFA9EC); + Xmid = _api.MemLib.ReadS32(0xFFA9EC); + Ymid = _api.MemLib.ReadS32(0xFFA9F0); + int Xvec = ((_api.MemLib.ReadS32(0xFFAA04) + Xmid) >> 16) - _camX; + int Yvec = ((_api.MemLib.ReadS32(0xFFAA08) + Ymid) >> 16) - _camY; + Xmid >>= 16; + Ymid >>= 16; + Xmid -= _camX; Ymid -= _camY; Width2 = _api.MemLib.ReadS16(0xFFA9FC); - Xmid -= _camX; - Ymid = _api.MemLib.ReadS16(0xFFA9F0); - Ymid -= _camY; Height2 = _api.MemLib.ReadS16(0xFFAA00); color = ((_api.MemLib.ReadU8(0xFFAA0C) != 0) ? Color.FromArgb(255, 0, 127) : Color.FromArgb(0, 0, 255)); DrawBoxMWH(Xmid, Ymid, Width2, Height2, color); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); - _api.GUILib.DrawPixel(Xmid, Ymid, color); + DrawBoxMWH(Xmid, Ymid, 1, 1, color, 0); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } //Pulsar curObj = _api.MemLib.ReadU24(0xFFCFD1); - if (curObj != 0) + if ((curObj != 0) && ((_api.MemLib.ReadU32(curObj + 0xC) == 0xC9222) || (_api.MemLib.ReadU32(curObj + 0xC) == 0xC9456))) { - // sbyte Blah = _api.MemLib.ReadU8(CardBoard + 0x15); curObj += 0x26; - // if (!(Blah & 1)) - // CardBoard += 0x14; for (int l = 0; l < 4; l++) { if (_api.MemLib.ReadU16(curObj + 0x12) != 0) { - Xmid = _api.MemLib.ReadS16(curObj); - Ymid = _api.MemLib.ReadS16(curObj + 4); + Xmid = _api.MemLib.ReadS32(curObj); + Ymid = _api.MemLib.ReadS32(curObj + 4); + int Xvec = (Xmid + _api.MemLib.ReadS32(curObj + 8) >> 16) - _camX; + int Yvec = (Ymid + _api.MemLib.ReadS32(curObj + 0xC) >> 16) - _camY; + Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 0x30, 0x30, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); - _api.GUILib.DrawPixel(Xmid, Ymid, Color.Red); + _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } curObj += 0x14; } } + + //Water Level + int waterLevel = _api.MemLib.ReadS16(0xFFA7B2); + _api.GUILib.DrawLine(0, waterLevel - _camY, _left + 320 + _right, waterLevel - _camY, Color.Aqua); + } void EccoAutofire(bool on) @@ -678,27 +2795,28 @@ namespace BizHawk.Client.EmuHawk uint mode = _api.MemLib.ReadU8(0xFFA555); int frameCount = _api.EmuLib.FrameCount(); int lagCount = _api.EmuLib.LagCount(); + _api.JoypadLib.Set("Start", on, 1); switch (mode) { case 0x00: if (on) { if (_api.MemLib.ReadU16(0xFFF342) == 0xFFFD) - _api.JoypadLib.Set("C", false, 1); - else _api.JoypadLib.Set("C", true, 1); + else + _api.JoypadLib.Set("C", false, 1); } break; case 0xE6: if (_api.MemLib.ReadU16(0xFFD5E8) == 0x00000002) { Dictionary buttons = new Dictionary(); - buttons["B"] = !(buttons["C"] = false); + buttons["B"] = buttons["C"] = true; _api.JoypadLib.Set(buttons, 1); } else { Dictionary buttons = new Dictionary(); - buttons["B"] = !(buttons["C"] = true); + buttons["B"] = buttons["C"] = false; _api.JoypadLib.Set(buttons, 1); } break; @@ -706,28 +2824,25 @@ namespace BizHawk.Client.EmuHawk charge = _api.MemLib.ReadU8(0xFFB19B); if (on) { - if ((charge == 1) || (_prevCharge == 1) || !(_prevOn || (_api.MemLib.ReadU8(0xFFB19B) != 0))) + if ((charge <= 1) && ((_api.MemLib.ReadU8(0xFFB1A6) == 0) || (_api.MemLib.ReadU8(0xFFB1A9) != 0))) _api.JoypadLib.Set("B", true, 1); - else + else if (charge > 1) _api.JoypadLib.Set("B", false, 1); - if ((_api.MemLib.ReadU16(0xFFB168) == 0x3800) && ((_api.MemLib.ReadU16(0xFFA7C8) % 2) != 0)) - _api.EmuLib.SetIsLagged(true); - _api.JoypadLib.Set("C", (_api.MemLib.ReadU16(0xFFA7C8) % 2) != 0, 1); + _api.JoypadLib.Set("C", (_api.MemLib.ReadU16(0xFFA7C8) % 2) == 0, 1); } - _prevCharge = charge; break; case 0x20: case 0x28: case 0xAC: if (on) { - _api.JoypadLib.Set("C", (_api.MemLib.ReadS8(0xFFAA6E) >= 11), 1); + if ((_api.MemLib.ReadU8(0xFFAB72) & 3) == 0) + _api.JoypadLib.Set("C", (_api.MemLib.ReadS8(0xFFAA6E) < 11), 1); } break; default: break; } - _prevOn = on; } public override void Init(IPluginAPI api) { @@ -741,7 +2856,9 @@ namespace BizHawk.Client.EmuHawk _mode = Modes.Ecco2; _camXAddr = 0xFFAD9C; _camYAddr = 0xFFAD9E; - EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); + _top = _bottom = 112; + _left = _right = 160; + EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); } else if ((gameName == "ECCO The Dolphin (J) [!]") || (gameName == "ECCO The Dolphin (UE) [!]")) @@ -750,7 +2867,9 @@ namespace BizHawk.Client.EmuHawk _mode = Modes.Ecco1; _camXAddr = 0xFFB836; _camYAddr = 0xFFB834; - EmuHawkPluginLibrary.SetGameExtraPadding(160,112,160,112); + _top = _bottom = 112; + _left = _right = 160; + EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); } else { @@ -758,41 +2877,564 @@ namespace BizHawk.Client.EmuHawk Running = false; } } + private Color BackdropColor() + { + uint color = _api.MemLib.ReadU16(0, "CRAM"); + int r = (int)(( color & 0x7) * 0x22); + int g = (int)(((color >> 3) & 0x7) * 0x22); + int b = (int)(((color >> 6) & 0x7) * 0x22); + return Color.FromArgb(r, g, b); + + } public override void PreFrameCallback() { + _api.GUILib.ClearText(); if (_mode != Modes.disabled) { - EccoAutofire(_api.JoypadLib.Get(1)["C"] != _api.JoypadLib.GetImmediate()["P1 C"]); + _camX = _api.MemLib.ReadS16(_camXAddr) - _left; + _camY = _api.MemLib.ReadS16(_camYAddr) - _top; + EccoAutofire(_api.JoypadLib.Get(1)["Start"]); + if (_dumpMap == 0) + { + Color bg = BackdropColor(); + _api.GUILib.DrawRectangle(0, 0, _left + 320 + _right, _top, bg, bg); + _api.GUILib.DrawRectangle(0, 0, _left, _top + 224 + _bottom, bg, bg); + _api.GUILib.DrawRectangle(_left + 320, 0, _left + 320 + _right, _top + 224 + _bottom, bg, bg); + _api.GUILib.DrawRectangle(0, _top + 224, _left + 320 + _right, _top + 224 + _bottom, bg, bg); + } + uint mode = _api.MemLib.ReadByte(0xFFA555); + switch (mode) + { + case 0x20: + case 0x28: + case 0xAC: + //EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); + if (_dumpMap <= 1) EccoDrawBoxes(); + // Uncomment the following block to enable mapdumping + /*if ((_api.MemLib.ReadU16(0xFFA7C8) > 1) && (_api.MemLib.ReadU16(0xFFA7C8) < 4)) + { + _dumpMap = 1; + _rowStateGuid = string.Empty; + _top = _bottom = _left = _right = 0; + EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + }*/ + if (_dumpMap == 3) + { + var levelID = _api.MemLib.ReadS8(0xFFA7D0); + int[] nameGroupLengths = + { + 7,1,11,6, + 4,3,3,3, + 7,1,2,1, + 0,0,0,0 + }; + int[] nameStringPtrOffsets = + { + 0xECBD0, 0x106BC0, 0x10AF8C, 0x135A48, + 0x1558E8, 0x15F700, 0x16537C, 0x180B00, + 0x193920, 0x1B3ECC, 0x1D7A44, 0x1DBF70, + 0x2DF2, 0x2DF6, 0x2DFA, 0x2DFE + }; + int nameGroup = 0; + var i = levelID; + while ((i >= 0) && (nameGroup < nameGroupLengths.Length)) + { + i -= nameGroupLengths[nameGroup]; + if (i >= 0) nameGroup++; + } + string name = "map"; + if (i < 0) + { + i += nameGroupLengths[nameGroup]; + uint strOffset = _api.MemLib.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); + Console.WriteLine($"{i}"); + strOffset = _api.MemLib.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); + strOffset += 0x20; + List strTmp = new List(); + byte c; + do + { + c = (byte)_api.MemLib.ReadByte(strOffset++); + if (c != 0) + strTmp.Add(c); + } while (c != 0); + name = System.Text.Encoding.ASCII.GetString(strTmp.ToArray()); + TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; + name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); + } + EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_top.png"); + _destX = _destY = 0; + EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + _dumpMap++; + } + if (_dumpMap == 6) + { + var levelID = _api.MemLib.ReadS8(0xFFA7D0); + int[] nameGroupLengths = + { + 7,1,11,6, + 4,3,3,3, + 7,1,2,1, + 0,0,0,0 + }; + int[] nameStringPtrOffsets = + { + 0xECBD0, 0x106BC0, 0x10AF8C, 0x135A48, + 0x1558E8, 0x15F700, 0x16537C, 0x180B00, + 0x193920, 0x1B3ECC, 0x1D7A44, 0x1DBF70, + 0x2DF2, 0x2DF6, 0x2DFA, 0x2DFE + }; + int nameGroup = 0; + var i = levelID; + while ((i >= 0) && (nameGroup < nameGroupLengths.Length)) + { + i -= nameGroupLengths[nameGroup]; + if (i >= 0) nameGroup++; + } + string name = "map"; + if (i < 0) + { + i += nameGroupLengths[nameGroup]; + uint strOffset = _api.MemLib.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); + Console.WriteLine($"{i}"); + strOffset = _api.MemLib.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); + strOffset += 0x20; + List strTmp = new List(); + byte c; + do + { + c = (byte)_api.MemLib.ReadByte(strOffset++); + if (c != 0) + strTmp.Add(c); + } while (c != 0); + name = System.Text.Encoding.ASCII.GetString(strTmp.ToArray()); + TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; + name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); + } + EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_bottom.png"); + _destX = _destY = 0; + _left = _right = 160; + _top = _bottom = 112; + EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); + _dumpMap = 0; + } + break; + case 0xF6: + EccoDraw3D(); + break; + default: + break; + } + _prevF = _api.MemLib.ReadU32(0xFFA524); } } public override void PostFrameCallback() { uint frame = _api.MemLib.ReadU32(0xFFA524); + if ((frame <= _prevF) && !_api.EmuLib.IsLagged()) + { + _api.EmuLib.SetIsLagged(true); + _api.EmuLib.SetLagCount(_api.EmuLib.LagCount() + 1); + } uint mode = _api.MemLib.ReadByte(0xFFA555); - switch (mode) { + _tickerY = 81; + string valueTicker = $"{_api.MemLib.ReadU32(0xFFA520)}:{_api.MemLib.ReadU32(0xFFA524)}:{_api.MemLib.ReadU16(0xFFA7C8)}:{mode:X2}"; + TickerText(valueTicker); + switch (mode) + { case 0x20: case 0x28: case 0xAC: - EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); - EccoDrawBoxes(); + valueTicker = $"{_api.MemLib.ReadS16(0xFFAD9C)}:{_api.MemLib.ReadS16(0xFFAD9E)}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFAA1A) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA1E) / 65536.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFAA32) / 65536.0:0.######}:{_api.MemLib.ReadU8(0xFFAA6D)}:{_api.MemLib.ReadU8(0xFFAA6E)}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFAA36) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA3A) / 65536.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFA9D6) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFA9DA) / 65536.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFAA3E) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA42) / 65536.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{(_api.MemLib.ReadS32(0xFFAA36) + _api.MemLib.ReadS32(0xFFA9D6) + _api.MemLib.ReadS32(0xFFAA3E)) / 65536.0:0.######}:" + + $"{(_api.MemLib.ReadS32(0xFFAA3A) + _api.MemLib.ReadS32(0xFFA9DA) + _api.MemLib.ReadS32(0xFFAA42)) / 65536.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadU8(0xFFAB72)}:{_api.MemLib.ReadU8(0xFFAB70)}:{(short)_api.MemLib.ReadS16(0xFFAA52):X4}:{(short)_api.MemLib.ReadS16(0xFFAA5A):X4}"; + TickerText(valueTicker); + switch (_api.MemLib.ReadU8(0xFFA7D0)) + { + case 1: + case 2: + case 3: + case 30: + case 46: + var globeFlags = _api.MemLib.ReadU32(0xFFD434) >> 1; + var globeFlags2 = _api.MemLib.ReadU32(0xFFD438) >> 1; + int i, j = i = 0; + while (globeFlags > 0) + { + globeFlags >>= 1; + i++; + } + while (globeFlags2 > 0) + { + globeFlags2 >>= 1; + j++; + } + TickerText($"{i}:{j}", Color.Blue); + break; + default: + break; + } + if (_dumpMap != 0) + { + _api.MemLib.WriteS16(0xFFAA16, 7); + _api.MemLib.WriteS16(0xFFAA18, 56); + int PlayerX = _api.MemLib.ReadS16(0xFFAA1A) - _camX; + int PlayerY = _api.MemLib.ReadS16(0xFFAA1E) - _camY; + if ((PlayerX < -64) || (PlayerX > 384) || (PlayerY < -64) || (PlayerY > 288)) + { + _api.MemLib.WriteByte(0xFFAA70, 0xC); + _api.MemLib.WriteS16(0xFFA7CA, 1); + } + else + { + _api.MemLib.WriteByte(0xFFAA70, 0x0); + _api.MemLib.WriteS16(0xFFA7CA, 0); + } + } + if (_dumpMap == 1) + { + int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); + int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); + var levelID = _api.MemLib.ReadByte(0xFFA7D0); + var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + s.DrawBGA = false; + s.DrawBGB = false; + s.DrawBGW = false; + s.DrawObj = false; + s.Backdrop = true; + _api.EmuLib.PutSettings(s); + if ((_camX == _destX) && (_camY == _destY)) + { + if ((_prevX != _camX) || (_prevY != _camY)) + { + if (_destX == 0) + { + if (_rowStateGuid != string.Empty) + { + _api.MemStateLib.DeleteState(_rowStateGuid); + } + _rowStateGuid = _api.MemStateLib.SaveCoreStateToMemory(); + } + _snapPast = 1; + } + else + { + _snapPast--; + } + if (_snapPast == 0) + { + EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_top.png"); + if (_destX >= levelWidth - 320) + { + if (_destY < levelHeight - 224) + { + if (_rowStateGuid != string.Empty) + { + _api.MemStateLib.LoadCoreStateFromMemory(_rowStateGuid); + } + _destX = 0; + _destY = Math.Min(_destY + 111, levelHeight - 224); + } + } + else + _destX = Math.Min(_destX + 159, levelWidth - 320); + if ((_prevX == _destX) && (_prevY == _destY)) + { + EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + _dumpMap++; + } + } + } + _api.MemLib.WriteS16(0xFFAD8C, _destX); + _api.MemLib.WriteS16(0xFFAD90, _destY); + } + else if (_dumpMap == 2) + { + if (_rowStateGuid != String.Empty) + _api.MemStateLib.DeleteState(_rowStateGuid); + _rowStateGuid = String.Empty; + int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); + int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); + EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + var levelID = _api.MemLib.ReadS8(0xFFA7D0); + var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + s.DrawBGA = false; + s.DrawBGB = false; + s.DrawBGW = false; + s.DrawObj = false; + s.Backdrop = true; + _api.EmuLib.PutSettings(s); + + var a = _api.GUILib.GetAttributes(); + a.SetColorKey(Color.FromArgb(0, 0x11, 0x22, 0x33), Color.FromArgb(0, 0x11, 0x22, 0x33)); + _api.GUILib.SetAttributes(a); + _api.GUILib.ToggleCompositingMode(); + + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_top.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); + for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) + { + var dx = (x == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_top.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); + } + for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) + { + var dy = (y == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_top.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); + for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) + { + var dx = (x == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_top.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); + } + } + + _api.GUILib.ToggleCompositingMode(); + _api.GUILib.SetAttributes(new System.Drawing.Imaging.ImageAttributes()); + _api.GUILib.DrawFinish(); + _dumpMap++; + } + else if (_dumpMap == 4) + { + int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); + int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); + var levelID = _api.MemLib.ReadByte(0xFFA7D0); + var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + s.DrawBGA = (levelID != 29); + s.DrawBGB = (levelID == 7); + s.DrawBGW = true; + s.DrawObj = true; + s.Backdrop = false; + _api.EmuLib.PutSettings(s); + if ((_camX == _destX) && (_camY == _destY)) + { + if ((_prevX != _camX) || (_prevY != _camY)) + { + if (_destX == 0) + { + if (_rowStateGuid != string.Empty) + { + _api.MemStateLib.DeleteState(_rowStateGuid); + } + _rowStateGuid = _api.MemStateLib.SaveCoreStateToMemory(); + } + _snapPast = 1; + } + else + { + _snapPast--; + } + if (_snapPast == 0) + { + EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_bottom.png"); + if (_destX >= levelWidth - 320) + { + if (_destY < levelHeight - 224) + { + if (_rowStateGuid != string.Empty) + { + _api.MemStateLib.LoadCoreStateFromMemory(_rowStateGuid); + } + _destX = 0; + _destY = Math.Min(_destY + 111, levelHeight - 224); + } + } + else + _destX = Math.Min(_destX + 159, levelWidth - 320); + if ((_prevX == _destX) && (_prevY == _destY)) + { + EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + _dumpMap++; + } + } + } + _api.MemLib.WriteS16(0xFFAD8C, _destX); + _api.MemLib.WriteS16(0xFFAD90, _destY); + } + else if (_dumpMap == 5) + { + if (_rowStateGuid != String.Empty) + _api.MemStateLib.DeleteState(_rowStateGuid); + _rowStateGuid = String.Empty; + int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); + int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); + var levelID = _api.MemLib.ReadS8(0xFFA7D0); + var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + s.DrawBGA = (levelID != 29); + s.DrawBGB = (levelID == 7); + s.DrawBGW = true; + s.DrawObj = true; + s.Backdrop = false; + _api.EmuLib.PutSettings(s); + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_bottom.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); + for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) + { + var dx = (x == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_bottom.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); + } + for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) + { + var dy = (y == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_bottom.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); + for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) + { + var dx = (x == 0) ? 0 : 2; + _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_bottom.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); + } + } + _api.GUILib.DrawFinish(); + _dumpMap++; + } + _prevX = _camX; + _prevY = _camY; break; case 0xF6: - EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); - EccoDraw3D(); + valueTicker = $"{_api.MemLib.ReadS32(0xFFD5E0) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD5E8) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD5E4) / 2048.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFB13A) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB142) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB13E) / 2048.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadS32(0xFFB162) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB16A) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB166) / 2048.0:0.######}"; + TickerText(valueTicker); + valueTicker = $"{_api.MemLib.ReadU8(0xFFB19B)}:{_api.MemLib.ReadU8(0xFFB1A6)}:{_api.MemLib.ReadU8(0xFFB1A9)}"; + TickerText(valueTicker); + int SpawnZ = _api.MemLib.ReadS32(0xFFD5F0) + 0x180000; + int nextRingZ = SpawnZ; + while (((nextRingZ >> 17) & 0xF) != 0) + { + nextRingZ += 0x20000; + } + valueTicker = $"{_api.MemLib.ReadS32(0xFFD856) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD85A) / 4096.0:0.######}:{(nextRingZ - 0x160000) / 2048.0:0.######}:{nextRingZ / 2048.0:0.######}"; + TickerText(valueTicker); + var levelId = -1 - _api.MemLib.ReadS16(0xFFA79E); + bool spawn = false; + bool firstRand = true; + int SpawnX, SpawnY, z; + int CamX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC) - _left; + int CamY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC) + _top; + int CamZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xC) + _top; + while (!spawn) + { + var temp = (SpawnZ >> 17) & 0xFF; + var controlList = _api.MemLib.ReadS32(0x7B54 + (levelId << 2)); + temp = _api.MemLib.ReadS16(controlList + (temp << 1)); + var v = temp & 0xFF; + var num = (temp >> 8) + v; + temp = v; + spawn = (num > 2); + if (spawn) for (; temp < num; temp++) + { + switch (temp) + { + case 0: + case 1: + case 13: + // Nothing important spawns + break; + case 2: + // Jellyfish + SpawnX = _api.MemLib.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); + firstRand = false; + SpawnY = -0xC0000 + (EccoRand() << 3); + z = SpawnZ + 0x20000;// ? + valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; + TickerText(valueTicker); + SpawnX = 160 + ((SpawnX >> 0xC) - CamX); + SpawnY = 112 - ((SpawnY >> 0xC) - CamY); + z = _top + 112 - ((z >> 0xC) - CamZ); + DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); + DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); + break; + case 3: + // Eagle + SpawnX = _api.MemLib.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); + firstRand = false; + SpawnY = 0x50000; + z = SpawnZ - 0x40000 + 0x20000;// ? + valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; + TickerText(valueTicker); + SpawnX = 160 + ((SpawnX >> 0xC) - CamX); + SpawnY = 112 - ((SpawnY >> 0xC) - CamY); + z = _top + 112 - ((z >> 0xC) - CamZ); + DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); + DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); + break; + case 4: + // Shark + bool left = (EccoRand(firstRand) > 0x8000); + firstRand = false; + var xdiff = 0xC0000 + (EccoRand() << 3); + SpawnX = _api.MemLib.ReadS32(0xFFB13A) + (left ? -xdiff : xdiff); + SpawnY = Math.Min(_api.MemLib.ReadS32(0xFFB142), -0x10000) - (EccoRand() + 0x10000); + z = SpawnZ + 0x20000; + valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; + TickerText(valueTicker); + SpawnX = 160 + ((SpawnX >> 0xC) - CamX); + SpawnY = 112 - ((SpawnY >> 0xC) - CamY); + z = _top + 112 - ((z >> 0xC) - CamZ); + DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); + DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); + break; + case 5: + case 6: + case 7: + case 8: + // Vine + EccoRand(firstRand); + firstRand = false; + if ((temp & 1) == 1) EccoRand(); + EccoRand(); + break; + case 9: + case 10: + case 11: + case 12: + // Unknown, possibly just rand incrementation? + EccoRand(firstRand); + firstRand = false; + if ((temp & 1) == 1) EccoRand(); + break; + case 14: + // Shell + SpawnX = _api.MemLib.ReadS32(0xFFB13A) - 0x20000 + (EccoRand(firstRand) << 2); + firstRand = false; + SpawnY = -0x80000; + z = SpawnZ + 0x20000; + EccoRand(); + valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{(z - 0x80000) / 2048.0:0.######}"; + TickerText(valueTicker); + SpawnX = 160 + ((SpawnX >> 0xC) - CamX); + SpawnY = 112 - ((SpawnY >> 0xC) - CamY); + z = _top + 112 - ((z >> 0xC) - CamZ); + DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); + DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); + break; + } + } + SpawnZ += 0x20000; + } break; - default: - EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); - break; } - _camX = _api.MemLib.ReadS16(_camXAddr)-160; - _camY = _api.MemLib.ReadS16(_camYAddr)-112; - if (frame <= _prevF) - _api.EmuLib.SetIsLagged(true); - _prevF = frame; + _api.JoypadLib.Set("C", null, 1); + _api.JoypadLib.Set("Start", null, 1); + var color = _turnSignalColors[_api.MemLib.ReadS8(0xFFA7C9) & 7]; + _api.GUILib.DrawRectangle(_left - 48, _top - 112, 15, 15, color, color); } public override void LoadStateCallback(string name) { - _prevF = _api.MemLib.ReadU32(0xFFA524); + _api.GUILib.DrawNew("emu"); + PreFrameCallback(); + _api.GUILib.DrawFinish(); } } } From 59f30b4a79a0bc904cea91d06d43696cf768df58 Mon Sep 17 00:00:00 2001 From: upthorn Date: Wed, 5 Dec 2018 12:07:10 -0800 Subject: [PATCH 008/440] Allow signed display of fixed point values. --- BizHawk.Client.Common/tools/Watch/DWordWatch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.Common/tools/Watch/DWordWatch.cs b/BizHawk.Client.Common/tools/Watch/DWordWatch.cs index 1e8c41f055..79a9ef03aa 100644 --- a/BizHawk.Client.Common/tools/Watch/DWordWatch.cs +++ b/BizHawk.Client.Common/tools/Watch/DWordWatch.cs @@ -217,9 +217,9 @@ namespace BizHawk.Client.Common case DisplayType.Hex: return val.ToHexString(8); case DisplayType.FixedPoint_20_12: - return $"{val / 4096.0:0.######}"; + return $"{(int)val / 4096.0:0.######}"; case DisplayType.FixedPoint_16_16: - return $"{val / 65536.0:0.######}"; + return $"{(int)val / 65536.0:0.######}"; case DisplayType.Float: var bytes = BitConverter.GetBytes(val); var _float = BitConverter.ToSingle(bytes, 0); From c50267fe96c66358c55069f19648f45eaf4db8a8 Mon Sep 17 00:00:00 2001 From: upthorn Date: Wed, 5 Dec 2018 12:07:53 -0800 Subject: [PATCH 009/440] GPGX trace no longer crashes when executing from M68K RAM. --- BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs index b6f867ace4..dfddf14bc7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs @@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx var regs = DebuggableCore.GetCpuFlagsAndRegisters(); uint pc = (uint)regs["M68K PC"].Value; var length = 0; - var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc, out length); + var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc & 0xFFFFFF, out length); var traceInfo = new TraceInfo { From 6f7a26e8037dde52146497002fe678820a015609 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 7 Dec 2018 15:03:19 +0000 Subject: [PATCH 010/440] Virtu: enable apple white and black keys --- .../Computers/AppleII/AppleII.cs | 4 ++-- BizHawk.sln | 21 ++++++++++++++++-- .../.vs/Virtu/v15/Server/sqlite3/db.lock | 0 .../.vs/Virtu/v15/Server/sqlite3/storage.ide | Bin 0 -> 573440 bytes .../Virtu/v15/Server/sqlite3/storage.ide-shm | Bin 0 -> 32768 bytes .../Virtu/v15/Server/sqlite3/storage.ide-wal | 0 ExternalCoreProjects/Virtu/GamePort.cs | 4 ++-- ExternalCoreProjects/Virtu/Keyboard.cs | 14 ++++++++++-- ExternalCoreProjects/Virtu/Virtu.csproj | 2 +- References/Virtu.dll | Bin 169472 -> 155648 bytes 10 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/db.lock create mode 100644 ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/storage.ide create mode 100644 ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/storage.ide-shm create mode 100644 ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/storage.ide-wal diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs index e67abf06ef..330d669ef8 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs @@ -115,8 +115,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII } private static readonly List RealButtons = new List(Keyboard.GetKeyNames() - .Where(k => k != "White Apple") // Hack because these buttons aren't wired up yet - .Where(k => k != "Black Apple") + //.Where(k => k != "White Apple") // Hack because these buttons aren't wired up yet + //.Where(k => k != "Black Apple") .Where(k => k != "Reset")); private static readonly List ExtraButtons = new List diff --git a/BizHawk.sln b/BizHawk.sln index 7f33fcf4e2..8e9fe65e66 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.136 MinimumVisualStudioVersion = 12.0.31101.0 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Version", "Version\Version.csproj", "{0CE8B337-08E3-4602-BF10-C4D4C75D2F13}" EndProject @@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.MultiHawk", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.ApiHawk", "BizHawk.Client.ApiHawk\BizHawk.Client.ApiHawk.csproj", "{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virtu", "ExternalCoreProjects\Virtu\Virtu.csproj", "{8E522778-7A2C-4364-BDCE-0BA5623828E1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -245,6 +247,18 @@ Global {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x64.Build.0 = Release|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.ActiveCfg = Release|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.Build.0 = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x64.ActiveCfg = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x64.Build.0 = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x86.ActiveCfg = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x86.Build.0 = Debug|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|Any CPU.Build.0 = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x64.ActiveCfg = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x64.Build.0 = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x86.ActiveCfg = Release|Any CPU + {8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -264,6 +278,9 @@ Global {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9B9E4316-9185-412E-B951-A63355ACA956} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = BizHawk.Client.EmuHawk\BizHawk.Client.EmuHawk.csproj EndGlobalSection diff --git a/ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/db.lock b/ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/db.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/storage.ide b/ExternalCoreProjects/Virtu/.vs/Virtu/v15/Server/sqlite3/storage.ide new file mode 100644 index 0000000000000000000000000000000000000000..9f73c3360aef75b5940ff9e47836383708a73765 GIT binary patch literal 573440 zcmeFa2Ygh;*FL_R-a~JKgwRVU2^}dR1ww}qY7jQbk}PbpVRsV1|~*E?K1>NoHs<< zq8mgViToyNT4WyB%A?W)l^&?{K&1yNJy7X^N)J?epwa`C9;oy{1$&^>KRCE{^XA6V z6sIZ6YEHIg7v-A^oXIAqse>C6k~AVEab!x&$i%*bQetA=;$mZ3M25xSh-JF8oY)vk zfzzC8w#O9OE%_#UNz7DpNlbyw8BQk>ZCNc#4MD-Rn>IC;CMi}7v)iVa zvxO0QI@sL?ebj&71pffNBhqcwBB#Yxpg6*f33NBYEzaADVv{{P&ve6%=oT1MdvJ53 z!BUW8p5d5g#nb0RQ<2lA@Dttgn%KdO4MM{RVdKd453U{8*jO5_q)B($Ed{x01(R(Z zCbBF#K0qx<#*nn(87VPoLy}X*#Kh_ZlmxLcwgR`%*cM7H$F>~i7gW1-YvWj@%2Zn& z=4nOdf^4$~>+j|>kH{7UrhIc7q-R8mlsFbL7k?%#m7U_sIM+Qaw6tOm9end<} zX!!o{P2nBGW5SMw?F>r^iw}J%^x@EPp#wvH2>CRmI3z11Jow$ zzt(;?`&IP|F#c-%+W3+24db)MM~n{`HyZCUmKlqTdB*X^A;v^wM`LqiJ!2%y{;wW2 z#`_!E-I88X;55w`X*ZkG*cy9XGX&GITU@91;UiV1OI*jU;pr;VDXwGZ@DVDL5ZAF|_;8i!5Z5t2 ze3)Poy2W*DA3juNy2K@P4IiR1o#GNYhYwbngt&x`;e%ABLtH|9_&~wLcZ*ACA3i{3 zy2QnI4Np^|mTgAnM2v*Fc2j;nx_aiw#Pm^? z9J9@l+1E0&ziIl^n7EjvVM&=OGn{67fytU=vzyhC(~&vKVs{p0YO15U`x_efLw_7* zvpbR1xNgX*TLosN(;e9rrAjI+;;_V0b*bP|X{w_-qf`UUC0RC;J%^?0RKcav>5lH` zZ)mDifLgBc3COHR1-ekLyhc2F>M*n2QkZA9qi#j{CUroTDHWKdR}Qt>`x_G2Y|_$_ zYz0oc&1yB<;n}Qq$T_V7bM}!(WLvd246$Uf-NYfwitY_Ubz~dlG}x4#XDKisCbznZ_|*Kr4h0kU4ah3aF2R*TFj12kE|kN)V`GL zn2MaoHbl-9-Is*w$eWQSS|P zQLZ+cnf9!}Ox?6sjY0z+VoSH$oJm$&Hb;dCk;t$j z8?d|jhzNf}Ltz6l8xxMqI#qb-pgA-QH`cf*1epfl3cldZ5w+ zl^&?{K&1yNJy7X^N)J?epwa`C9;o!d{|ygB8~qy_bxRG#hoM~K4Oa}oXZ+^*rTTUA zYvb3@ubN+=@rv;q|G0JbE zU%KH+NOtHWArax5BTxC?8s5lnNyz!YdSMBHcSp4kKM?u8f4<*6A^!=C4@(WaFQSpZ zpZ|MNsX@O*w+)I8dos8<(iw4gWN^TvA=5)&4(}8+H*|c|lL0BwJ0rsUe)NAa$Pjj4 zuqo(bU;E9y`{$Dk?E>;LPOQq#Yk(d+&H_z3?7M*04KoMia^f2?Hq z{(p>Q`2K&iWcdDnl*%aY|1%`R_x~d$!}tH`lHvRR5t8Bi|KTd5y#F628NUA?DjB~2 zA0ipP{~s(FzW*PjGRph^fs*0-{{fQW`~Nh_@cn;($?*MuKb2A5|EEfZ@BdRI!}tHm zlHvRRB+2mof8TKbo9INo|4$6_uS**5|NE#U-v9SjNtC`WfARkR zmT>{4U5pht(Wa^H5se<8dq>}Wd_ZZpip)x_hGgI(|cn@tKRO{&PeRX4jbXxh;~ z-}p~o)HfLwP}>pq4k-Wqe6HMvM(8?NsrlgXVDFSc@0+Vai}$ zfp^eCZ7A=?&^z7V|A$xtN;4|5MDkkdl~XXEG~{dgpfLfZ2^E>GR2;|w$HzPQfT;nc zV=FR4Sxz5$`G@+~MoICe-VeRLM`#6BrJ_}R|Idy65z#04Al*6oTJ+`U|3rTqeKGoc z^heR}MZXk%GWxCPQ~&j+?8=mt9;oy{r3WfKQ0akx?148&8H39FOLug}JZ*lK%_{b3 zO}6!#IN0noU(jINzqW{xmVHru&LFGhXt|{%Bk=?}2lx|Eqc6fS*rC60+d2Vv9Fl;gLPN8b)XSWp1lU8Efq?555t5|97=!khXt!m|#X(i63LT%m}KO@^*$c~{45gYeh0jZ{J zv(}h~(4CfS_rO8sf?Q{wd)Q!0fzM#m3}3;+u)ziU1>IH1x`TP{5zw77BimZ!z?KKE zn6v`lF{T;ir7_JYC(TH77i+R5*Wz@zXM<5osa0Qbqw}zhI=v8H^GJiA^>R7Yy{Rjl zzJ;gdpn+PPC1{RlK_+Z0cBLExSLM05i~i%tAfMy|kq{XV(k&ZnV z=m-u?&cbf!*;&)|q27JdE!tPt6asGDOAGRy8HEQ~9GcZyg6rpiiqmyE?DBGzO*ho* zI;S$i_v79ZZ6MPmQ>`YQchqoQZ73mVPt3%O4J9DeV)B%Pk0x%W)n>{u=SYDu4lDjUl_oI52~xC8bIwS+sldVC>tpm_hwVSN%1E@uvnK`Xl}EC&I|U8i6Ma5%WS%gq;na7P&flUdXYa z=cB6yp9udsv|CtGNTG;98Le^18 zX;45}w6`t)W*zymBe*m)psc319sjmZ)Byz#fNcj^3Z~H|LFJ4r|E5cPm=RbS5KtEW zKk5-UBVbxUsrhe=_@`Gn*V_R{<`DCAC#JjbQlRYshpm9__sZr#(r zR9|ecc1f)|;oRr<)of9-Q@COUlU@Jp{=j{c_LN0DJpb_5H48eIbR4(6zOm7e zvnM8={%qc$pZDGK=i||)I_4Rx8g2|tn)S5*dkt644onEz>g+l%Y}eHHgNmN+l^Nar z*5r4GZc16zvfrYsA-6Qkm{%{o%bJCC27EYa$)%;w-uCEC=cChaJyg`7cj>P6i(l=s z^!L0E{O7+{fByY5pRF66-|n5zhkH$!8avYb$>gyM2i*C=;9Ga@Ilt-8Zad$PZqxU~ zhN+G*W8^&dI%O7QWx zS09h;ceHF*$j9b44zBIcWpw6@`-e=Q({1^<+OO65`O=CJpQf4~d$>zRpYxBD1no1u zY`EHfRkP5Xh^F7~p3)-W_7{q4RXLy6G^_aR-Tm`wpL%L(-Tv#JoxQ8e&V@NkmNpr= zwnK|Li{D$=&h*l${;zaTjA@hfTJuN0wnf~Y`Ptc{1yhDJ=>6I|@0}l8?YGSLKAd&Q ze(g+r>CJmtM@#k|KBH>kON*tlsopR9B1;Sc7%H)L|C>9e;MO^U5~M^Q=1pHH5+ z|DDu3FD?y!BJ}*z13O+jIAUsQhgCJ&M+7}M=*rjkum9ucUsp#S*%_L%FzfyB1{r0Wla|E6Jm=e+b&;)2H?YW(EH zX%Pk0lG|+yHic}jdi=dJPyBHB&>Iga_n zH(Z*y;J%}civvshuS>}8@7z6l^Lwk#+*U?b@Zp z!`=GVe|vGaSJRrWsx|c3(b*fCy}SP2x88ldo-uG*lMjBmv-goz2_tN=2gWZ5KVdn3 zG5M;!-SZ<}i8xa|ee3!vFNHpxp8Zz6pB5cCm^mwV=%;Bh7m8;#cDy=g^zP@Te15gf z))zm2sO+YhGvg*(_mz~i=s!NM;fCauM;2D!-gM}sjlVvcncpY!U{du#J>Oh1;rRTS zkIZknZpOanV_P0t_h4}FXUk7FIXTVt*6qft_pIOk;=G0vp1Cb7XGp};ow_}-cm7K` zO9QLFx3b0~Bl=k9#@3#8?&oBMh=e!ltUEk8Va zt;v^DZ{OPNscV)^_M+G)PWHMMGAi$7j$C(B0tOC zn@hf#T|Bz)$fth%cwLXMvRoz{svj==~@8O}-dSAHtu45tJ zPiWGz_v_0tXH~uZ&7MhRPn}!${p!?9^R|Ef>$^?*9Q-ynzU2?4UpzH`!5<&C|6*tN z%%jKF&$^m$rvJmgEiQ}h{eJ5|av!eq_@T{XUa`Dz-v8yDmzI6;#f7a;Ul}~N+wsn? zZeMwBT4t+$S4!>+?YDo<&eW?3O{)FX`sw_qY*iaPbg$p2*o>_oe)&xNwr{#Po^RTG z%E5(anmxSU)bPVuf2_Zh7Z(1}Gk%*3FK4W4Wtn2#H+;($<6WON?qGU;M(wOC!{!}* z@z;9CBHH*5->|jzS7(=0>$3gMA<4VfbU0#r_>Nw`men>FHP0xxFn;UrBmbHepSf|u z#Rn&~J(4{pZJYmNBko+%ZE^FZrenPij!I2#d92j~pVjIXGsvELdU5UDe>8evPu+{n zOAanP_{q+$i7)?F&v0+nXKF@A^W@ zjzNM^>#wj==1iU#*Io(o?@PO_RTMf&%X3~?K{pzwyL|_ z8gQ!YaQmNMI9j$Sd&&d*PJ}*nZukA$=FD%?Zf@5*AFa1%=C3Q)eDms<;LAz9Z5a~` zz3VplrM2myG_4z&5pL=28nqA><^sjsLoxl}C+B7^o>h!(mOLsh0eDA8@+XA8wpB}!s*7VNx zj(>M%NzJb=wm(Qd~Ewgg+MyxJq9N6-$ zfzK{(HlXeJR~8&jzPH)Aoi#$2-}-CsMIX$3=F$t7h9{+G{IuS0$Cg8Vhi80$^v~8i zA3X5zj0JaJ{Uc!ik8jkueaMuIZ~dnbnvHx zXKK8?b<578cYpnJe312?H7|UYH8uWHSo3Qs=Sv#@r)SyILFow>7da<}qWM*@Uqn{Eiafuj(Qxp|EW;!ORP!?!g8Z?4)({ju0IPCJ zCR-eNZIwNkA^sG20^njyrVOg$xd%POFUYS&OZ=_wk+>~XW+BNrfXR74EVPBH0ck>l zvY_;5L`Z?4u(Se;(}JBNGtD7^l$eUxPud#{TnNe|C=e@9%}y<{tb_Rcvl1CH(uTdN zSQo9u&xlt)%f-ZDSe=SxuTB#fM_KF=+!xLpA7EI}U)&d-`nK=o=YB9wsJ*s{y{g0c z&WWvWP2znai%uBSD_1R$V+M~t)87Fjl%RjHO9h`C!AyR-S?AB3k~93ecF8f{xr^!BcCuMBAAMA9BR<)j|V;)>lig)#XI#r%V{yO z(JfzIPKdOA5HYz&T;@j?KAC>!17|Haec1B0O&?Eu`Td|(SEE+$>pSz!tjFs-IyGs@ zbHM&YcqVz*8H?1r<;b&Z1q%)xz*MBtARG(rb*Ab!B>81vT})O_(vUQT}jz&OoMTrHJT|UldsAv+qXi$u4twH{ zmp(uE=!eHgoqe#yb31-p+I#wkJx4eE<@aMVkG~xBi#2`4XX9%{?TV;dV?>iTt3;3Z zrt8sZ(YFO!t@V7F``v36ZpgTtOxfZ>4$KDH%Hwnvl<=mzIekZH%JKuaz_|lG# zuh_Hii{qa!n0fcQnzoMfAN|ki+#OqvUp~EQaKrld-Bog-=C)a}Q$Kt;VC8b$v}b%j z^0~DSq7B#=^jLgOG@B(e)n>D*{S(7~nSZ(Zq@a3l%xzS%{P?LKWV7KSaO06aF(3YU zG;;F!)T?S;jYjaB_kHx-mKi_$KUXU(uI-R_4xY%YHRa)L_JBRxni`Jo*tewq>X2{h ze>b=1D}FI6)^F>)-B!K%Bi44kOMBRY4!t|DXF|tGx#LcC{-W*0T1!9bIeYT4fmO<8 zrhI;%zO&9pXIs9Y4>A*-BB+YzruXu@>pY~9@2G=9N0?1Hefi;rpvEnnc@{^EP}C+S ztHfy@KcNjj&DbUe`%p-5HTtWdJApt>6uA^MZL1+&N%EfK=baZB! zHYkJ^j<(rzf~tGyko`Xw{R1D(a*bX=q3KgCg`!Z^+|#&nL6RrEOvZv%i$KPaC)N|tGd)p z4>xkT1*GK`V0EK=5ck*RxQAgGkGcg@6b_an2VuQ*losMGgWrV75^1N^UACC?G43kbNka#sL$z!sw^+r87WB&rs-?Y*)eu_vm1(wswY zQ(hm*i-Oolrw>iF%)qv8lhvAK%AV?(L>pYLD@M)bsThrYciy=wp+1tJ;GSQGgH6eJ zAkYoi;#cN$wwmqeU1DFmG9bA{xiQ$CiVb;UOQ6tbw!7+F@vxea***$;D~KW)1-S7Ln;CP| zjjB57a$=bhpbFtZq{g2wV^Au$Vvf^5?30*W_mjh%B)@{;3l4S?LGp7^3ZXkcffJQ32 zqLtx93c?guHxySp^^)j{khdr-1$S`b%w{K2rP6R^Td*4J>RmG9f?Oe~L?|Xfa%hpW zun1c<)xGi}kuD=T6=JRi3z{X)VK~~eK1v%A5DFJe6;fc5u%sHj%WOv@Fp=k3y`2C{ zUFxP`Y$WA}p%JJXWyz^uM%R(pbDk?@)mXLm)vf_qQD-g!gRyA-2w|qMt032$lPG_Y zz-y?`3F&*JXRuO*qJcuIs}^2I&Y)2U>S1&yyr>6L@i)9`Bz`~)(}m4vUlioM5e@NgoJzi{-z zlM3fedIHn2QYR%JzKfs?Kj2Q9;mrXgQRI5ye6vb(AF~V}3%afvZpXQvO2<_dkAr-2-39%W zVY=Hv*T)%V8G1s7c~NEnXxc{lV+eAth&D_>MzojoSCC;k%Ctr}=WQ654w~VV2?ot_ zF}%M@GyHe8ybO<5!)a4BoqSJScnY3nsfT&(fO6@d5y+JOdM{haHf1F zXx0VkwE)Z288`$zd_<<7Pk@$nv`p1m2W{XDD1=%=Ea=a4^il-k=~6i+gN7@V@|r-9 zW?plkoaG~JM!=u8lA@)d`>* zsq_iZY#U7bG3XX59fW{}D%}C$vaXvVoW7_0S^VKlB7O3sjt+tIrGILHmVRpnn*O1D zchD?5>4BhWKj~X_GIr2X{}RyERGIZUdLL-1{}^bg6QYVAcs>v1^e27T3c@$x%)BB% zv+Sf_1!x27`V)Zpl3oUdvTe_U@o)5a3uqo40|c4C#H4k-pdtVM%`johYWF za}mOsmUCHx`?$}qeYL0I;g`XFd0 z(?)=n`kU$K&Y)%69fq{BjQtSKzRI+ZA|dl)zOR6mHcZpm*%N8uYDK0Ngy{#$_W)g6 zrAL6~SkLg^k&(3LE1j>lL67wRS)G0>(!wMq?Ux9bG9?I?bOW9J55Y+4XI^RQm`MLD zfIRD(;eSFv%Itx>te0m&%QEI6Q`v^+fJSn~CqLIoD3+bCc z!#st~1Wi2*x9MbNfo5I|UjdprNpA%$(>@5A{$%(|py^N27eKS_NdE|0>JP*Ppn)3x z5^e(6{wdQ1;Zo17pkvhVxu9cJdOv8^BjtyHmiEMgmUcc3TH5fTPM$Bn=tHL60nq29 zzlRLRanktatkN$?;~U#9{jY$QGGFL?-WK7~4_gsV{q%Vsgv-2!gO+2|y|^KOn39(n zv@HAmpruSN_)6+Lf^ezlInW%hXUqZfmg z_QXM6>Ul(`=NS}=HqieYba|acxEyo#>B64`EzABn=vu08uYuk1})phH#$B3x;o_# z>_|V9LXXVr9BA2=q98z-(Lfpko8wIXv;oaNNct*_k#r%#nJ>d@fu>JLZ`aA+p$o49 z<5?EU97njkhiHIs))&KnLAbon=zwtgis8LbDU@N|^hbCDHM|+h1y=FlMmSuKjc*~G z{^7OwZ4?Sas8X&YkU^9}n~_kCduJg-+gSFWbo7gmrwqf3bn=~`gyS~rZXv>9wqj>P zq$N#xb||(1(jTE-7*6>o5GeB+19>@aw}CuZMScSci>9SK^UOwGq^ajo&`is6JqMaP zNe7~U^aJTqgi|N!8VIKir0>pbS_5Yyvg|$AKq-s{q$x{E0IkDExq~AX!F` zhV}saP;;OFSPHBH)&Q(4`kCWkJD>xQ0E_@e0wGYqwx0pq4cq}lBJ5F|9|j%)9s`~M zz6bsT`~(C-CK_lAIvD54IOhY6KsNwlfO+8A{^kSKfWZKLG8=dbs0W$mKr_&kV_k)V z=e@*g&^P1E{)(zs;$&T!z_Y$sNA&-vIJ1t~<}L$O5w;Fzjxh|A^-f>1{u!pvrzv

3n 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�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 /// Call this at 60hz with all of the currently pressed keys ///

@@ -272,8 +275,15 @@ namespace Jellyfish.Virtu { Keys keys = FromStrings(keynames); - if (keys.HasFlag(Keys.WhiteApple)) { } // TODO: set GAME1 - if (keys.HasFlag(Keys.BlackApple)) { } // TODO: set GAME2 + if (keys.HasFlag(Keys.WhiteApple)) + WhiteAppleDown = true; + else + WhiteAppleDown = false; + + if (keys.HasFlag(Keys.BlackApple)) + BlackAppleDown = true; + else + BlackAppleDown = false; if (keys.HasFlag(Keys.Reset) && keys.HasFlag(Keys.Control)) { } // TODO: reset console diff --git a/ExternalCoreProjects/Virtu/Virtu.csproj b/ExternalCoreProjects/Virtu/Virtu.csproj index ad68f03108..e3e9fc67b1 100644 --- a/ExternalCoreProjects/Virtu/Virtu.csproj +++ b/ExternalCoreProjects/Virtu/Virtu.csproj @@ -74,7 +74,7 @@
- copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\references\$(TargetFileName) + copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\references\$(TargetFileName)" - + \ No newline at end of file diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs b/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs similarity index 91% rename from BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs rename to BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs index b0ccf94061..3677007d2b 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Emu.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Collections.Generic; +using BizHawk.Client.Common; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Nintendo.NES; @@ -12,11 +13,32 @@ using BizHawk.Emulation.Cores.Sega.MasterSystem; using BizHawk.Emulation.Cores.WonderSwan; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { [Description("A library for interacting with the currently loaded emulator core")] - public sealed class EmulatorPluginLibrary : PluginLibraryBase + public sealed class EmuApi : IEmu { + private static class EmuStatic + { + public static void DisplayVsync(bool enabled) + { + Global.Config.VSync = enabled; + } + public static string GetSystemId() + { + return Global.Game.System; + } + public static void LimitFramerate(bool enabled) + { + Global.Config.ClockThrottle = enabled; + } + + public static void MinimizeFrameskip(bool enabled) + { + Global.Config.AutoMinimizeSkipping = enabled; + } + + } [RequiredService] private IEmulator Emulator { get; set; } @@ -41,12 +63,12 @@ namespace BizHawk.Client.Common public Action FrameAdvanceCallback { get; set; } public Action YieldCallback { get; set; } - public EmulatorPluginLibrary() : base() + public EmuApi() { } - public static void DisplayVsync(bool enabled) + public void DisplayVsync(bool enabled) { - Global.Config.VSync = enabled; + EmuStatic.DisplayVsync(enabled); } public void FrameAdvance() @@ -166,9 +188,9 @@ namespace BizHawk.Client.Common } } - public static string GetSystemId() + public string GetSystemId() { - return Global.Game.System; + return EmuStatic.GetSystemId(); } public bool IsLagged() @@ -217,14 +239,39 @@ namespace BizHawk.Client.Common } } - public static void LimitFramerate(bool enabled) + public void LimitFramerate(bool enabled) { - Global.Config.ClockThrottle = enabled; + EmuStatic.LimitFramerate(enabled); } - public static void MinimizeFrameskip(bool enabled) + public void MinimizeFrameskip(bool enabled) { - Global.Config.AutoMinimizeSkipping = enabled; + EmuStatic.MinimizeFrameskip(enabled); + } + + public void Yield() + { + YieldCallback(); + } + + public string GetDisplayType() + { + if (RegionableCore != null) + { + return RegionableCore.Region.ToString(); + } + + return ""; + } + + public string GetBoardName() + { + if (BoardInfo != null) + { + return BoardInfo.BoardName; + } + + return ""; } public object GetSettings() { @@ -407,30 +454,5 @@ namespace BizHawk.Client.Common return true; } - - public void Yield() - { - YieldCallback(); - } - - public string GetDisplayType() - { - if (RegionableCore != null) - { - return RegionableCore.Region.ToString(); - } - - return ""; - } - - public string GetBoardName() - { - if (BoardInfo != null) - { - return BoardInfo.BoardName; - } - - return ""; - } } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs b/BizHawk.Client.ApiHawk/Classes/Api/GameInfoApi.cs similarity index 85% rename from BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs rename to BizHawk.Client.ApiHawk/Classes/Api/GameInfoApi.cs index e74ea5f21b..ca74d09da6 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Gameinfo.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/GameInfoApi.cs @@ -1,16 +1,16 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using BizHawk.Client.Common; using BizHawk.Emulation.Common; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class GameInfoPluginLibrary : PluginLibraryBase + public sealed class GameInfoApi : IGameInfo { [OptionalService] private IBoardInfo BoardInfo { get; set; } - public GameInfoPluginLibrary() : base() + public GameInfoApi() { } public string GetRomName() diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs b/BizHawk.Client.ApiHawk/Classes/Api/JoypadApi.cs similarity index 97% rename from BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs rename to BizHawk.Client.ApiHawk/Classes/Api/JoypadApi.cs index 5eeb3ff1e6..0c049ed97c 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Joypad.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/JoypadApi.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; -namespace BizHawk.Client.Common +using BizHawk.Client.Common; + +namespace BizHawk.Client.ApiHawk { - public sealed class JoypadPluginLibrary : PluginLibraryBase + public sealed class JoypadApi : IJoypad { - public JoypadPluginLibrary() : base() + public JoypadApi() { } public Dictionary Get(int? controller = null) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs b/BizHawk.Client.ApiHawk/Classes/Api/MemApi.cs similarity index 95% rename from BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs rename to BizHawk.Client.ApiHawk/Classes/Api/MemApi.cs index 543ea1780b..f54b282550 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Memory.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/MemApi.cs @@ -5,20 +5,16 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Common.BufferExtensions; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class MemoryPluginLibrary : PluginMemoryBase + public sealed class MemApi : MemApiBase, IMem { private MemoryDomain _currentMemoryDomain; private bool _isBigEndian = false; - public MemoryPluginLibrary() + public MemApi() : base() { } - public void SetBigEndian() - { - _isBigEndian = true; - } protected override MemoryDomain Domain { @@ -44,6 +40,11 @@ namespace BizHawk.Client.Common #region Unique Library Methods + public void SetBigEndian(bool enabled = true) + { + _isBigEndian = enabled; + } + public List GetMemoryDomainList() { var list = new List(); @@ -198,16 +199,16 @@ namespace BizHawk.Client.Common return (sbyte)ReadUnsignedByte(addr, domain); } - public void WriteS8(long addr, uint value, string domain = null) - { - WriteUnsignedByte(addr, value, domain); - } - public uint ReadU8(long addr, string domain = null) { return (byte)ReadUnsignedByte(addr, domain); } + public void WriteS8(long addr, int value, string domain = null) + { + WriteSigned(addr, value, 1, domain); + } + public void WriteU8(long addr, uint value, string domain = null) { WriteUnsignedByte(addr, value, domain); diff --git a/BizHawk.Client.Common/plugins/PluginMemoryBase.cs b/BizHawk.Client.ApiHawk/Classes/Api/MemApiBase.cs similarity index 97% rename from BizHawk.Client.Common/plugins/PluginMemoryBase.cs rename to BizHawk.Client.ApiHawk/Classes/Api/MemApiBase.cs index 21bf8b89e0..bc5c328d66 100644 --- a/BizHawk.Client.Common/plugins/PluginMemoryBase.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/MemApiBase.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { /// /// Base class for the Memory and MainMemory plugin libraries /// - public abstract class PluginMemoryBase : PluginLibraryBase + public abstract class MemApiBase : IExternalApi { [RequiredService] protected IEmulator Emulator { get; set; } @@ -18,7 +18,7 @@ namespace BizHawk.Client.Common protected abstract MemoryDomain Domain { get; } - protected PluginMemoryBase() : base() + protected MemApiBase() { } protected IMemoryDomains DomainList diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs b/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs similarity index 89% rename from BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs rename to BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs index 9816e9344d..5848df5fc3 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.MemoryEvents.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs @@ -3,14 +3,14 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class MemoryEventsPluginLibrary : PluginLibraryBase + public sealed class MemEventsApi : IMemEvents { [RequiredService] private IDebuggable DebuggableCore { get; set; } - public MemoryEventsPluginLibrary () : base() + public MemEventsApi () : base() { } public void AddReadCallback(Action cb, uint address, string domain) diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs b/BizHawk.Client.ApiHawk/Classes/Api/MemorySaveStateApi.cs similarity index 87% rename from BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs rename to BizHawk.Client.ApiHawk/Classes/Api/MemorySaveStateApi.cs index 90950d6f73..b22eaa7540 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.MemorySavestate.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/MemorySaveStateApi.cs @@ -4,11 +4,11 @@ using System.IO; using BizHawk.Emulation.Common; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class MemorySavestatePluginLibrary : PluginLibraryBase + public sealed class MemorySaveStateApi : IMemorySaveState { - public MemorySavestatePluginLibrary() : base() + public MemorySaveStateApi() { } [RequiredService] diff --git a/BizHawk.Client.ApiHawk/Classes/Api/MovieApi.cs b/BizHawk.Client.ApiHawk/Classes/Api/MovieApi.cs new file mode 100644 index 0000000000..0b74cfd5cc --- /dev/null +++ b/BizHawk.Client.ApiHawk/Classes/Api/MovieApi.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.ApiHawk +{ + public sealed class MovieApi : IMovie + { + private static class MoviePluginStatic + { + public static string Filename() + { + return Global.MovieSession.Movie.Filename; + } + + public static bool GetReadOnly() + { + return Global.MovieSession.ReadOnly; + } + + public static ulong GetRerecordCount() + { + return Global.MovieSession.Movie.Rerecords; + } + + public static bool GetRerecordCounting() + { + return Global.MovieSession.Movie.IsCountingRerecords; + } + + public static bool IsLoaded() + { + return Global.MovieSession.Movie.IsActive; + } + + public static double Length() + { + return Global.MovieSession.Movie.FrameCount; + } + + public static string Mode() + { + if (Global.MovieSession.Movie.IsFinished) + { + return "FINISHED"; + } + + if (Global.MovieSession.Movie.IsPlaying) + { + return "PLAY"; + } + + if (Global.MovieSession.Movie.IsRecording) + { + return "RECORD"; + } + + return "INACTIVE"; + } + + public static void SetReadOnly(bool readOnly) + { + Global.MovieSession.ReadOnly = readOnly; + } + + public static void SetRerecordCount(double count) + { + // Lua numbers are always double, integer precision holds up + // to 53 bits, so throw an error if it's bigger than that. + const double PrecisionLimit = 9007199254740992d; + + if (count > PrecisionLimit) + { + throw new Exception("Rerecord count exceeds Lua integer precision."); + } + + Global.MovieSession.Movie.Rerecords = (ulong)count; + } + + public static void SetRerecordCounting(bool counting) + { + Global.MovieSession.Movie.IsCountingRerecords = counting; + } + + public static void Stop() + { + Global.MovieSession.Movie.Stop(); + } + + public static double GetFps() + { + if (Global.MovieSession.Movie.IsActive) + { + var movie = Global.MovieSession.Movie; + var system = movie.HeaderEntries[HeaderKeys.PLATFORM]; + var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) && + movie.HeaderEntries[HeaderKeys.PAL] == "1"; + + return new PlatformFrameRates()[system, pal]; + } + + return 0.0; + } + + } + public MovieApi() + { } + + public bool StartsFromSavestate() + { + return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSavestate; + } + + public bool StartsFromSaveram() + { + return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSaveRam; + } + + public Dictionary GetInput(int frame) + { + if (!Global.MovieSession.Movie.IsActive) + { + Console.WriteLine("No movie loaded"); + return null; + } + + var input = new Dictionary(); + var adapter = Global.MovieSession.Movie.GetInputState(frame); + + if (adapter == null) + { + Console.WriteLine("Can't get input of the last frame of the movie. Use the previous frame"); + return null; + } + + foreach (var button in adapter.Definition.BoolButtons) + { + input[button] = adapter.IsPressed(button); + } + + foreach (var button in adapter.Definition.FloatControls) + { + input[button] = adapter.GetFloat(button); + } + + return input; + } + + public string GetInputAsMnemonic(int frame) + { + if (Global.MovieSession.Movie.IsActive && frame < Global.MovieSession.Movie.InputLogLength) + { + var lg = Global.MovieSession.LogGeneratorInstance(); + lg.SetSource(Global.MovieSession.Movie.GetInputState(frame)); + return lg.GenerateLogEntry(); + } + + return ""; + } + + public void Save(string filename = "") + { + if (!Global.MovieSession.Movie.IsActive) + { + return; + } + + if (!string.IsNullOrEmpty(filename)) + { + filename += "." + Global.MovieSession.Movie.PreferredExtension; + var test = new FileInfo(filename); + if (test.Exists) + { + Console.WriteLine($"File {filename} already exists, will not overwrite"); + return; + } + + Global.MovieSession.Movie.Filename = filename; + } + + Global.MovieSession.Movie.Save(); + } + + public Dictionary GetHeader() + { + var table = new Dictionary(); + if (Global.MovieSession.Movie.IsActive) + { + foreach (var kvp in Global.MovieSession.Movie.HeaderEntries) + { + table[kvp.Key] = kvp.Value; + } + } + + return table; + } + + public List GetComments() + { + var list = new List(Global.MovieSession.Movie.Comments.Count); + if (Global.MovieSession.Movie.IsActive) + { + for (int i = 0; i < Global.MovieSession.Movie.Comments.Count; i++) + { + list[i] = Global.MovieSession.Movie.Comments[i]; + } + } + + return list; + } + + public List GetSubtitles() + { + var list = new List(Global.MovieSession.Movie.Subtitles.Count); + if (Global.MovieSession.Movie.IsActive) + { + for (int i = 0; i < Global.MovieSession.Movie.Subtitles.Count; i++) + { + list[i] = Global.MovieSession.Movie.Subtitles[i].ToString(); + } + } + + return list; + } + + public string Filename() + { + return MoviePluginStatic.Filename(); + } + + public bool GetReadOnly() + { + return MoviePluginStatic.GetReadOnly(); + } + + public ulong GetRerecordCount() + { + return MoviePluginStatic.GetRerecordCount(); + } + + public bool GetRerecordCounting() + { + return MoviePluginStatic.GetRerecordCounting(); + } + + public bool IsLoaded() + { + return MoviePluginStatic.IsLoaded(); + } + + public double Length() + { + return MoviePluginStatic.Length(); + } + + public string Mode() + { + return MoviePluginStatic.Mode(); + } + + public void SetReadOnly(bool readOnly) + { + MoviePluginStatic.SetReadOnly(readOnly); + } + + public void SetRerecordCount(double count) + { + MoviePluginStatic.SetRerecordCount(count); + } + + public void SetRerecordCounting(bool counting) + { + MoviePluginStatic.SetRerecordCounting(counting); + } + + public void Stop() + { + MoviePluginStatic.Stop(); + } + + public double GetFps() + { + return MoviePluginStatic.GetFps(); + } + } +} diff --git a/BizHawk.Client.Common/plugins/PluginBase.cs b/BizHawk.Client.ApiHawk/Classes/Api/PluginBase.cs similarity index 89% rename from BizHawk.Client.Common/plugins/PluginBase.cs rename to BizHawk.Client.ApiHawk/Classes/Api/PluginBase.cs index 7ef2f4453d..24bf62c727 100644 --- a/BizHawk.Client.Common/plugins/PluginBase.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/PluginBase.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { public abstract class PluginBase : IPlugin { @@ -13,7 +13,7 @@ namespace BizHawk.Client.Common /// or register memory callbacks in /// their Init function. /// - protected IPluginAPI _api; + protected IApiContainer _api; public PluginBase() { } @@ -41,7 +41,7 @@ namespace BizHawk.Client.Common public virtual void LoadStateCallback(string name) { } public virtual void InputPollCallback() { } public virtual void ExitCallback() { } - public virtual void Init (IPluginAPI api) + public virtual void Init (IApiContainer api) { _api = api; Running = true; diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs b/BizHawk.Client.ApiHawk/Classes/Api/SqlApi.cs similarity index 95% rename from BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs rename to BizHawk.Client.ApiHawk/Classes/Api/SqlApi.cs index dae76333af..6a18d507af 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.SQL.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/SqlApi.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data.SQLite; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class SQLPluginLibrary : PluginLibraryBase + public sealed class SqlApi : ISql { - public SQLPluginLibrary() : base() + public SqlApi() : base() { } SQLiteConnection m_dbConnection; @@ -125,6 +125,5 @@ namespace BizHawk.Client.Common return sqlEX.Message; } } - } } diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs b/BizHawk.Client.ApiHawk/Classes/Api/UserDataApi.cs similarity index 84% rename from BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs rename to BizHawk.Client.ApiHawk/Classes/Api/UserDataApi.cs index 27d2dc5af4..735fe397b9 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.UserData.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/UserDataApi.cs @@ -3,11 +3,11 @@ using System.ComponentModel; using BizHawk.Client.Common; -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { - public sealed class UserDataPluginLibrary : PluginLibraryBase + public sealed class UserDataApi : IUserData { - public UserDataPluginLibrary() : base() + public UserDataApi() : base() { } public void Set(string name, object value) diff --git a/BizHawk.Client.ApiHawk/Classes/ApiInjector.cs b/BizHawk.Client.ApiHawk/Classes/ApiInjector.cs new file mode 100644 index 0000000000..811807659f --- /dev/null +++ b/BizHawk.Client.ApiHawk/Classes/ApiInjector.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; + +using BizHawk.Common.ReflectionExtensions; + +namespace BizHawk.Client.ApiHawk +{ + /// + /// injects Apis into other classes + /// + public static class ApiInjector + { + /// + /// clears all Apis from a target + /// + public static void ClearApis(object target) + { + Type targetType = target.GetType(); + object[] tmp = new object[1]; + + foreach (var propinfo in + targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute)) + .Concat(targetType.GetPropertiesWithAttrib(typeof(OptionalApiAttribute)))) + { + propinfo.GetSetMethod(true).Invoke(target, tmp); + } + } + + /// + /// Feeds the target its required Apis. + /// + /// false if update failed + public static bool UpdateApis(IExternalApiProvider source, object target) + { + Type targetType = target.GetType(); + object[] tmp = new object[1]; + + foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute))) + { + tmp[0] = source.GetApi(propinfo.PropertyType); + if (tmp[0] == null) + { + return false; + } + + propinfo.GetSetMethod(true).Invoke(target, tmp); + } + + foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(OptionalApiAttribute))) + { + tmp[0] = source.GetApi(propinfo.PropertyType); + propinfo.GetSetMethod(true).Invoke(target, tmp); + } + + return true; + } + + /// + /// Determines whether a target is available, considering its dependencies + /// and the Apis provided by the emulator core. + /// + public static bool IsAvailable(IExternalApiProvider source, Type targetType) + { + return targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute)) + .Select(pi => pi.PropertyType) + .All(source.HasApi); + } + } + + [AttributeUsage(AttributeTargets.Property)] + public class RequiredApiAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Property)] + public class OptionalApiAttribute : Attribute + { + } +} diff --git a/BizHawk.Client.ApiHawk/Classes/BasicApiProvider.cs b/BizHawk.Client.ApiHawk/Classes/BasicApiProvider.cs new file mode 100644 index 0000000000..75da59a6d4 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Classes/BasicApiProvider.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BizHawk.Client.ApiHawk +{ + /// + /// A generic implementation of IExternalApi provider that provides + /// this functionality to any core. + /// The provider will scan an IExternal and register all IExternalApis + /// that the core object itself implements. In addition it provides + /// a Register() method to allow the core to pass in any additional Apis + /// + /// + public class BasicApiProvider : IExternalApiProvider + { + private readonly Dictionary _Apis = new Dictionary(); + + public BasicApiProvider(IApiContainer container) + { + // simplified logic here doesn't scan for possible Apis; just adds what it knows is implemented by the PluginApi + // this removes the possibility of automagically picking up a Api in a nested class, (find the type, then + // find the field), but we're going to keep such logic out of the basic provider. Anything the passed + // container doesn't implement directly needs to be added with Register() + // this also fully allows apis that are not IExternalApi + var libs = container.Libraries; + + _Apis = libs; + } + + /// + /// the client can call this to register an additional Api + /// + /// The to register + public void Register(T api) + where T : IExternalApi + { + if (api == null) + { + throw new ArgumentNullException(nameof(api)); + } + + _Apis[typeof(T)] = api; + } + + public T GetApi() + where T : IExternalApi + { + return (T)GetApi(typeof(T)); + } + + public object GetApi(Type t) + { + IExternalApi Api; + KeyValuePair[] k = _Apis.Where(kvp => t.IsAssignableFrom(kvp.Key)).ToArray(); + if (k.Length > 0) + { + return k[0].Value; + } + + return null; + } + + public bool HasApi() + where T : IExternalApi + { + return HasApi(typeof(T)); + } + + public bool HasApi(Type t) + { + return _Apis.ContainsKey(t); + } + + public IEnumerable AvailableApis + { + get + { + return _Apis.Select(d => d.Key); + } + } + } +} diff --git a/BizHawk.Client.ApiHawk/Classes/ClientApi.cs b/BizHawk.Client.ApiHawk/Classes/ClientApi.cs index 767d755105..8756885f54 100644 --- a/BizHawk.Client.ApiHawk/Classes/ClientApi.cs +++ b/BizHawk.Client.ApiHawk/Classes/ClientApi.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; using BizHawk.Client.Common; +using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.Sega.MasterSystem; @@ -21,6 +22,9 @@ namespace BizHawk.Client.ApiHawk { #region Fields + private static IEmulator Emulator; + private static IVideoProvider VideoProvider; + private static readonly Assembly clientAssembly; private static readonly object clientMainFormInstance; private static readonly Type mainFormClass; @@ -68,24 +72,57 @@ namespace BizHawk.Client.ApiHawk mainFormClass = clientAssembly.GetType("BizHawk.Client.EmuHawk.MainForm"); } + public static void UpdateEmulatorAndVP(IEmulator emu = null) + { + Emulator = emu; + VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu); + } + #endregion #region Methods + #region Helpers + + private static void InvokeMainFormMethod(string name, dynamic[] paramList = null) + { + List typeList = new List(); + MethodInfo method; + if (paramList != null) + { + foreach (var obj in paramList) + { + typeList.Add(obj.GetType()); + } + method = mainFormClass.GetMethod(name, typeList.ToArray()); + } + else method = mainFormClass.GetMethod(name); + method.Invoke(clientMainFormInstance, paramList); + } + + private static object GetMainFormField(string name) + { + return mainFormClass.GetField(name); + } + + private static void SetMainFormField(string name, object value) + { + mainFormClass.GetField(name).SetValue(clientMainFormInstance, value); + } + + #endregion + #region Public /// /// THE FrameAdvance stuff /// public static void DoFrameAdvance() { - MethodInfo method = mainFormClass.GetMethod("FrameAdvance"); - method.Invoke(clientMainFormInstance, null); + InvokeMainFormMethod("FrameAdvance", null); - method = mainFormClass.GetMethod("StepRunLoop_Throttle", BindingFlags.NonPublic | BindingFlags.Instance); - method.Invoke(clientMainFormInstance, null); + InvokeMainFormMethod("StepRunLoop_Throttle", null); - method = mainFormClass.GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance); - method.Invoke(clientMainFormInstance, null); + InvokeMainFormMethod("Render", null); } /// @@ -124,8 +161,7 @@ namespace BizHawk.Client.ApiHawk /// Savetate friendly name public static void LoadState(string name) { - MethodInfo method = mainFormClass.GetMethod("LoadState"); - method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false }); + InvokeMainFormMethod("LoadState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false }); } @@ -194,12 +230,11 @@ namespace BizHawk.Client.ApiHawk /// /// Raise when a rom is successfully Loaded /// - public static void OnRomLoaded() + public static void OnRomLoaded(IEmulator emu) { - if (RomLoaded != null) - { - RomLoaded(null, EventArgs.Empty); - } + Emulator = emu; + VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu); + RomLoaded?.Invoke(null, EventArgs.Empty); allJoypads = new List(RunningSystem.MaxControllers); for (int i = 1; i <= RunningSystem.MaxControllers; i++) @@ -215,11 +250,9 @@ namespace BizHawk.Client.ApiHawk /// Savetate friendly name public static void SaveState(string name) { - MethodInfo method = mainFormClass.GetMethod("SaveState"); - method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false }); + InvokeMainFormMethod("SaveState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false }); } - /// /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements /// @@ -227,24 +260,23 @@ namespace BizHawk.Client.ApiHawk /// Top padding /// Right padding /// Bottom padding - public static void SetExtraPadding(int left, int top, int right, int bottom) + public static void SetGameExtraPadding(int left, int top, int right, int bottom) { FieldInfo f = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin").GetField("DisplayManager"); object displayManager = f.GetValue(null); - f = f.FieldType.GetField("ClientExtraPadding"); + f = f.FieldType.GetField("GameExtraPadding"); f.SetValue(displayManager, new Padding(left, top, right, bottom)); - MethodInfo resize = mainFormClass.GetMethod("FrameBufferResized"); - resize.Invoke(clientMainFormInstance, null); + InvokeMainFormMethod("FrameBufferResized"); } /// /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements /// /// Left padding - public static void SetExtraPadding(int left) + public static void SetGameExtraPadding(int left) { - SetExtraPadding(left, 0, 0, 0); + SetGameExtraPadding(left, 0, 0, 0); } /// @@ -252,9 +284,9 @@ namespace BizHawk.Client.ApiHawk /// /// Left padding /// Top padding - public static void SetExtraPadding(int left, int top) + public static void SetGameExtraPadding(int left, int top) { - SetExtraPadding(left, top, 0, 0); + SetGameExtraPadding(left, top, 0, 0); } /// @@ -263,9 +295,56 @@ namespace BizHawk.Client.ApiHawk /// Left padding /// Top padding /// Right padding - public static void SetExtraPadding(int left, int top, int right) + public static void SetGameExtraPadding(int left, int top, int right) { - SetExtraPadding(left, top, right, 0); + SetGameExtraPadding(left, top, right, 0); + } + + /// + /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements + /// + /// Left padding + /// Top padding + /// Right padding + /// Bottom padding + public static void SetClientExtraPadding(int left, int top, int right, int bottom) + { + FieldInfo f = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin").GetField("DisplayManager"); + object displayManager = f.GetValue(null); + f = f.FieldType.GetField("ClientExtraPadding"); + f.SetValue(displayManager, new Padding(left, top, right, bottom)); + + InvokeMainFormMethod("FrameBufferResized"); + } + + /// + /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements + /// + /// Left padding + public static void SetClientExtraPadding(int left) + { + SetClientExtraPadding(left, 0, 0, 0); + } + + /// + /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements + /// + /// Left padding + /// Top padding + public static void SetClientExtraPadding(int left, int top) + { + SetClientExtraPadding(left, top, 0, 0); + } + + /// + /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements + /// + /// Left padding + /// Top padding + /// Right padding + public static void SetClientExtraPadding(int left, int top, int right) + { + SetClientExtraPadding(left, top, right, 0); } @@ -327,8 +406,7 @@ namespace BizHawk.Client.ApiHawk /// public static void UnpauseEmulation() { - MethodInfo method = mainFormClass.GetMethod("UnpauseEmulator"); - method.Invoke(clientMainFormInstance, null); + InvokeMainFormMethod("UnpauseEmulator", null); } #endregion Public @@ -375,6 +453,275 @@ namespace BizHawk.Client.ApiHawk } } + public static void CloseEmulator() + { + InvokeMainFormMethod("CloseEmulator"); + } + + public static void CloseEmulatorWithCode(int exitCode) + { + InvokeMainFormMethod("CloseEmulator", new object[] {exitCode}); + } + + public static int BorderHeight() + { + var point = new System.Drawing.Point(0, 0); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin"); + FieldInfo f = t.GetField("DisplayManager"); + object displayManager = f.GetValue(null); + MethodInfo m = t.GetMethod("TransFormPoint"); + point = (System.Drawing.Point) m.Invoke(displayManager, new object[] { point }); + return point.Y; + } + + public static int BorderWidth() + { + var point = new System.Drawing.Point(0, 0); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin"); + FieldInfo f = t.GetField("DisplayManager"); + object displayManager = f.GetValue(null); + MethodInfo m = t.GetMethod("TransFormPoint"); + point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point }); + return point.X; + } + + public static int BufferHeight() + { + return VideoProvider.BufferHeight; + } + + public static int BufferWidth() + { + return VideoProvider.BufferWidth; + } + + public static void ClearAutohold() + { + InvokeMainFormMethod("ClearHolds"); + } + + public static void CloseRom() + { + InvokeMainFormMethod("CloseRom"); + } + + public static void DisplayMessages(bool value) + { + Global.Config.DisplayMessages = value; + } + + public static void EnableRewind(bool enabled) + { + InvokeMainFormMethod("EnableRewind", new object[] {enabled}); + } + + public static void FrameSkip(int numFrames) + { + if (numFrames > 0) + { + Global.Config.FrameSkip = numFrames; + InvokeMainFormMethod("FrameSkipMessage"); + } + else + { + Console.WriteLine("Invalid frame skip value"); + } + } + + public static int GetTargetScanlineIntensity() + { + return Global.Config.TargetScanlineFilterIntensity; + } + + public static int GetWindowSize() + { + return Global.Config.TargetZoomFactors[Emulator.SystemId]; + } + + public static void SetSoundOn(bool enable) + { + Global.Config.SoundEnabled = enable; + } + + public static bool GetSoundOn() + { + return Global.Config.SoundEnabled; + } + + public static bool IsPaused() + { + return (bool) GetMainFormField("EmulatorPaused"); + } + + public static bool IsTurbo() + { + return (bool)GetMainFormField("IsTurboing"); + } + + public static bool IsSeeking() + { + return (bool)GetMainFormField("IsSeeking"); + } + + public static void OpenRom(string path) + { + var ioa = OpenAdvancedSerializer.ParseWithLegacy(path); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin.MainForm.LoadRomArgs"); + object o = Activator.CreateInstance(t); + t.GetField("OpenAdvanced").SetValue(o, ioa); + + InvokeMainFormMethod("LoadRom", new object[] {path, o}); + } + + public static void Pause() + { + InvokeMainFormMethod("PauseEmulator"); + } + + public static void PauseAv() + { + SetMainFormField("PauseAvi", true); + } + + public static void RebootCore() + { + InvokeMainFormMethod("RebootCore"); + } + + public static void SaveRam() + { + InvokeMainFormMethod("FlushSaveRAM"); + } + + public static int ScreenHeight() + { + Type t = GetMainFormField("PresentationPanel").GetType(); + object o = GetMainFormField("PresentationPanel"); + o = t.GetField("NativeSize").GetValue(o); + t = t.GetField("NativeSize").GetType(); + + return (int) t.GetField("Height").GetValue(o); + } + + public static void Screenshot(string path = null) + { + if (path == null) + { + InvokeMainFormMethod("TakeScreenshot"); + } + else + { + InvokeMainFormMethod("TakeScreenshot", new object[] {path}); + } + } + + public static void ScreenshotToClipboard() + { + InvokeMainFormMethod("TakeScreenshotToClipboard"); + } + + public static void SetTargetScanlineIntensity(int val) + { + Global.Config.TargetScanlineFilterIntensity = val; + } + + public static void SetScreenshotOSD(bool value) + { + Global.Config.Screenshot_CaptureOSD = value; + } + + public static int ScreenWidth() + { + Type t = GetMainFormField("PresentationPanel").GetType(); + object o = GetMainFormField("PresentationPanel"); + o = t.GetField("NativeSize").GetValue(o); + t = t.GetField("NativeSize").GetType(); + + return (int) t.GetField("Width").GetValue(o); + } + + public static void SetWindowSize(int size) + { + if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10) + { + Global.Config.TargetZoomFactors[Emulator.SystemId] = size; + InvokeMainFormMethod("FrameBufferResized"); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin"); + FieldInfo f = t.GetField("OSD"); + object osd = f.GetValue(null); + t = f.GetType(); + MethodInfo m = t.GetMethod("AddMessage"); + m.Invoke(osd, new Object[] { "Window size set to " + size + "x" }); + } + else + { + Console.WriteLine("Invalid window size"); + } + } + + public static void SpeedMode(int percent) + { + if (percent > 0 && percent < 6400) + { + InvokeMainFormMethod("ClickSpeedItem", new object[] {percent}); + } + else + { + Console.WriteLine("Invalid speed value"); + } + } + + public static void TogglePause() + { + InvokeMainFormMethod("TogglePause"); + } + + public static int TransformPointX(int x) + { + var point = new System.Drawing.Point(x, 0); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin"); + FieldInfo f = t.GetField("DisplayManager"); + object displayManager = f.GetValue(null); + MethodInfo m = t.GetMethod("TransFormPoint"); + point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point }); + return point.X; + } + + public static int TransformPointY(int y) + { + var point = new System.Drawing.Point(0, y); + Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin"); + FieldInfo f = t.GetField("DisplayManager"); + object displayManager = f.GetValue(null); + MethodInfo m = t.GetMethod("TransFormPoint"); + point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point }); + return point.Y; + } + + public static void Unpause() + { + InvokeMainFormMethod("UnpauseEmulator"); + } + + public static void UnpauseAv() + { + SetMainFormField("PauseAvi", false); + } + + public static int Xpos() + { + object o = GetMainFormField("DesktopLocation"); + Type t = mainFormClass.GetField("DesktopLocation").GetType(); + return (int)t.GetField("X").GetValue(o); + } + + public static int Ypos() + { + object o = GetMainFormField("DesktopLocation"); + Type t = mainFormClass.GetField("DesktopLocation").GetType(); + return (int)t.GetField("Y").GetValue(o); + } + #endregion #region Properties @@ -427,11 +774,11 @@ namespace BizHawk.Client.ApiHawk } else { - return SystemInfo.DualGB; + return SystemInfo.DualGB; } default: - return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId)); + return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId)); } } } diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IApiContainer.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IApiContainer.cs new file mode 100644 index 0000000000..ec169fee9d --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IApiContainer.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IApiContainer + { + Dictionary Libraries { get; set; } + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IComm.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IComm.cs new file mode 100644 index 0000000000..9ef8a5e0c0 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IComm.cs @@ -0,0 +1,35 @@ +namespace BizHawk.Client.ApiHawk +{ + public interface IComm : IExternalApi + { + #region Sockets + string SocketServerScreenShot(); + string SocketServerScreenShotResponse(); + string SocketServerSend(string SendString); + string SocketServerResponse(); + bool SocketServerSuccessful(); + void SocketServerSetTimeout(int timeout); + #endregion + + #region MemoryMappedFiles + void MmfSetFilename(string filename); + string MmfSetFilename(); + int MmfScreenshot(); + int MmfWrite(string mmf_filename, string outputString); + string MmfRead(string mmf_filename, int expectedSize); + #endregion + + #region HTTP + string HttpTest(); + string HttpTestGet(); + string HttpGet(string url); + string HttpPost(string url, string payload); + string HttpPostScreenshot(); + void HttpSetTimeout(int timeout); + void HttpSetPostUrl(string url); + void HttpSetGetUrl(string url); + string HttpGetPostUrl(); + string HttpGetGetUrl(); + #endregion + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IEmu.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IEmu.cs new file mode 100644 index 0000000000..51136126ac --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IEmu.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IEmu : IExternalApi + { + Action FrameAdvanceCallback { get; set; } + Action YieldCallback { get; set; } + void DisplayVsync(bool enabled); + void FrameAdvance(); + int FrameCount(); + object Disassemble(uint pc, string name = ""); + ulong? GetRegister(string name); + Dictionary GetRegisters(); + void SetRegister(string register, int value); + long TotalExecutedycles(); + string GetSystemId(); + bool IsLagged(); + void SetIsLagged(bool value = true); + int LagCount(); + void SetLagCount(int count); + void LimitFramerate(bool enabled); + void MinimizeFrameskip(bool enabled); + void Yield(); + string GetDisplayType(); + string GetBoardName(); + object GetSettings(); + bool PutSettings(object settings); + void SetRenderPlanes(params bool[] param); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IExternalApi.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IExternalApi.cs new file mode 100644 index 0000000000..8dc7c9da03 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IExternalApi.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Client.ApiHawk +{ + /// + /// This interface specifies that a client exposes a given interface, such as , + /// for use by external tools. + /// + public interface IExternalApi + { + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IGameInfo.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IGameInfo.cs new file mode 100644 index 0000000000..814a6d268c --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IGameInfo.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IGameInfo : IExternalApi + { + string GetRomName(); + string GetRomHash(); + bool InDatabase(); + string GetStatus(); + bool IsStatusBad(); + string GetBoardType(); + Dictionary GetOptions(); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IGui.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IGui.cs new file mode 100644 index 0000000000..03e3247e51 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IGui.cs @@ -0,0 +1,51 @@ +using System.Drawing; +using System.Drawing.Imaging; +using System.Windows.Forms; + +namespace BizHawk.Client.ApiHawk +{ + public interface IGui : IExternalApi + { + #region Gui API + void ToggleCompositingMode(); + ImageAttributes GetAttributes(); + void SetAttributes(ImageAttributes a); + void DrawNew(string name, bool? clear = true); + void DrawFinish(); + bool HasGUISurface { get; } + #endregion + + #region Helpers + void SetPadding(int all); + void SetPadding(int x, int y); + void SetPadding(int l, int t, int r, int b); + Padding GetPadding(); + #endregion + + void AddMessage(string message); + void ClearGraphics(); + void ClearText(); + void SetDefaultForegroundColor(Color color); + void SetDefaultBackgroundColor(Color color); + void SetDefaultTextBackground(Color color); + void SetDefaultPixelFont(string fontfamily); + void DrawBezier(Point p1, Point p2, Point p3, Point p4, Color? color = null); + void DrawBeziers(Point[] points, Color? color = null); + void DrawBox(int x, int y, int x2, int y2, Color? line = null, Color? background = null); + void DrawEllipse(int x, int y, int width, int height, Color? line = null, Color? background = null); + void DrawIcon(string path, int x, int y, int? width = null, int? height = null); + void DrawImage(string path, int x, int y, int? width = null, int? height = null, bool cache = true); + void ClearImageCache(); + void DrawImageRegion(string path, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int? dest_width = null, int? dest_height = null); + void DrawLine(int x1, int y1, int x2, int y2, Color? color = null); + void DrawAxis(int x, int y, int size, Color? color = null); + void DrawPie(int x, int y, int width, int height, int startangle, int sweepangle, Color? line = null, Color? background = null); + void DrawPixel(int x, int y, Color? color = null); + void DrawPolygon(Point[] points, Color? line = null, Color? background = null); + void DrawRectangle(int x, int y, int width, int height, Color? line = null, Color? background = null); + void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null, + string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null); + void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null); + void Text(int x, int y, string message, Color? forecolor = null, string anchor = null); + } +} \ No newline at end of file diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IInput.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IInput.cs new file mode 100644 index 0000000000..507bb024bf --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IInput.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IInput : IExternalApi + { + Dictionary Get(); + Dictionary GetMouse(); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IJoypad.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IJoypad.cs new file mode 100644 index 0000000000..1a8ce3340a --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IJoypad.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IJoypad : IExternalApi + { + Dictionary Get(int? controller = null); + + // TODO: what about float controls? + Dictionary GetImmediate(); + void SetFromMnemonicStr(string inputLogEntry); + void Set(Dictionary buttons, int? controller = null); + void Set(string button, bool? state = null, int? controller = null); + void SetAnalog(Dictionary controls, object controller = null); + void SetAnalog(string control, float? value = null, object controller = null); + + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IMem.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IMem.cs new file mode 100644 index 0000000000..7c8961ac5f --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IMem.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + public interface IMem : IExternalApi + { + void SetBigEndian(bool enabled = true); + + #region Domains + List GetMemoryDomainList(); + uint GetMemoryDomainSize(string name = ""); + string GetCurrentMemoryDomain(); + uint GetCurrentMemoryDomainSize(); + bool UseMemoryDomain(string domain); + string HashRegion(long addr, int count, string domain = null); + #endregion + #region Read + #region Special and Legacy Methods + uint ReadByte(long addr, string domain = null); + List ReadByteRange(long addr, int length, string domain = null); + float ReadFloat(long addr, string domain = null); + #endregion + #region Signed + int ReadS8(long addr, string domain = null); + int ReadS16(long addr, string domain = null); + int ReadS24(long addr, string domain = null); + int ReadS32(long addr, string domain = null); + #endregion + #region Unsigned + uint ReadU8(long addr, string domain = null); + uint ReadU16(long addr, string domain = null); + uint ReadU24(long addr, string domain = null); + uint ReadU32(long addr, string domain = null); + #endregion + #endregion + #region Write + #region Special and Legacy Methods + void WriteByte(long addr, uint value, string domain = null); + void WriteByteRange(long addr, List memoryblock, string domain = null); + void WriteFloat(long addr, double value, string domain = null); + #endregion + #region Signed + void WriteS8(long addr, int value, string domain = null); + void WriteS16(long addr, int value, string domain = null); + void WriteS24(long addr, int value, string domain = null); + void WriteS32(long addr, int value, string domain = null); + #endregion + #region Unigned + void WriteU8(long addr, uint value, string domain = null); + void WriteU16(long addr, uint value, string domain = null); + void WriteU24(long addr, uint value, string domain = null); + void WriteU32(long addr, uint value, string domain = null); + #endregion + #endregion + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs new file mode 100644 index 0000000000..b8650a9139 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs @@ -0,0 +1,12 @@ +using System; + +namespace BizHawk.Client.ApiHawk +{ + public interface IMemEvents : IExternalApi + { + void AddReadCallback(Action cb, uint address, string domain); + void AddWriteCallback(Action cb, uint address, string domain); + void AddExecCallback(Action cb, uint address, string domain); + void RemoveMemoryCallback(Action cb); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IMemorySavestate.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemorySavestate.cs new file mode 100644 index 0000000000..e3444c7bb5 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemorySavestate.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Client.ApiHawk +{ + public interface IMemorySaveState : IExternalApi + { + string SaveCoreStateToMemory(); + void LoadCoreStateFromMemory(string identifier); + void DeleteState(string identifier); + void ClearInMemoryStates(); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IMovie.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IMovie.cs new file mode 100644 index 0000000000..c983ec1df1 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IMovie.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +namespace BizHawk.Client.ApiHawk +{ + public interface IMovie : IExternalApi + { + bool StartsFromSavestate(); + bool StartsFromSaveram(); + string Filename(); + Dictionary GetInput(int frame); + string GetInputAsMnemonic(int frame); + bool GetReadOnly(); + ulong GetRerecordCount(); + bool GetRerecordCounting(); + bool IsLoaded(); + double Length(); + string Mode(); + void Save(string filename = ""); + void SetReadOnly(bool readOnly); + void SetRerecordCount(double count); + void SetRerecordCounting(bool counting); + void Stop(); + double GetFps(); + Dictionary GetHeader(); + List GetComments(); + List GetSubtitles(); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/ISaveState.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/ISaveState.cs new file mode 100644 index 0000000000..8f595610fe --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/ISaveState.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Client.ApiHawk +{ + public interface ISaveState : IExternalApi + { + void Load(string path); + void LoadSlot(int slotNum); + void Save(string path); + void SaveSlot(int slotNum); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/ISql.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/ISql.cs new file mode 100644 index 0000000000..99407ac1c2 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/ISql.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Client.ApiHawk +{ + public interface ISql : IExternalApi + { + string CreateDatabase(string name); + string OpenDatabase(string name); + string WriteCommand(string query = ""); + dynamic ReadCommand(string query = ""); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/ITool.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/ITool.cs new file mode 100644 index 0000000000..ce4cdce516 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/ITool.cs @@ -0,0 +1,16 @@ +using System; +namespace BizHawk.Client.ApiHawk +{ + public interface ITool : IExternalApi + { + Type GetTool(string name); + object CreateInstance(string name); + void OpenCheats(); + void OpenHexEditor(); + void OpenRamWatch(); + void OpenRamSearch(); + void OpenTasStudio(); + void OpenToolBox(); + void OpenTraceLogger(); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IUserData.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IUserData.cs new file mode 100644 index 0000000000..234a7d4695 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IUserData.cs @@ -0,0 +1,11 @@ +namespace BizHawk.Client.ApiHawk +{ + public interface IUserData : IExternalApi + { + void Set(string name, object value); + object Get(string key); + void Clear(); + bool Remove(string key); + bool ContainsKey(string key); + } +} diff --git a/BizHawk.Client.ApiHawk/Interfaces/IExternalApiProvider.cs b/BizHawk.Client.ApiHawk/Interfaces/IExternalApiProvider.cs new file mode 100644 index 0000000000..d44299f7b1 --- /dev/null +++ b/BizHawk.Client.ApiHawk/Interfaces/IExternalApiProvider.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace BizHawk.Client.ApiHawk +{ + /// + /// This interface defines the mechanism by which External tools can retrieve + /// from a client implementation + /// An implementation should collect all available IExternalApi instances. + /// This interface defines only the external interaction. This interface does not specify the means + /// by which a api provider will be populated with available apis. However, an implementation + /// by design must provide this mechanism + /// + /// + public interface IExternalApiProvider + { + /// e + /// Returns whether or not T is available + /// + /// The to check + bool HasApi() where T : IExternalApi; + + /// + /// Returns whether or not t is available + /// + bool HasApi(Type t); + + /// + /// Returns an instance of T if T is available + /// Else returns null + /// + /// The requested + T GetApi() where T : IExternalApi; + + /// + /// Returns an instance of t if t is available + /// Else returns null + /// + object GetApi(Type t); + + /// + /// Gets a list of all currently registered Apis available to be retrieved + /// + IEnumerable AvailableApis { get; } + } +} diff --git a/BizHawk.Client.Common/plugins/IPlugin.cs b/BizHawk.Client.ApiHawk/Interfaces/IPlugin.cs similarity index 73% rename from BizHawk.Client.Common/plugins/IPlugin.cs rename to BizHawk.Client.ApiHawk/Interfaces/IPlugin.cs index 9220e90dbd..444ecec8b2 100644 --- a/BizHawk.Client.Common/plugins/IPlugin.cs +++ b/BizHawk.Client.ApiHawk/Interfaces/IPlugin.cs @@ -1,4 +1,4 @@ -namespace BizHawk.Client.Common +namespace BizHawk.Client.ApiHawk { interface IPlugin { @@ -7,6 +7,6 @@ void SaveStateCallback(string name); void LoadStateCallback(string name); void InputPollCallback(); - void Init(IPluginAPI api); + void Init(IApiContainer api); } } diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index f3bcc12f20..84c1eed24d 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -260,6 +260,7 @@ + diff --git a/BizHawk.Client.EmuHawk/OpenAdvanced.cs b/BizHawk.Client.Common/OpenAdvanced.cs similarity index 94% rename from BizHawk.Client.EmuHawk/OpenAdvanced.cs rename to BizHawk.Client.Common/OpenAdvanced.cs index 9a9cfc1c91..b26bff967e 100644 --- a/BizHawk.Client.EmuHawk/OpenAdvanced.cs +++ b/BizHawk.Client.Common/OpenAdvanced.cs @@ -10,7 +10,7 @@ using Newtonsoft.Json; //this file contains some cumbersome self-"serialization" in order to gain a modicum of control over what the serialized output looks like //I don't want them to look like crufty json -namespace BizHawk.Client.EmuHawk +namespace BizHawk.Client.Common { public interface IOpenAdvanced { @@ -74,7 +74,7 @@ namespace BizHawk.Client.EmuHawk } } - class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro + public class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro { public OpenAdvanced_Libretro() { @@ -103,7 +103,7 @@ namespace BizHawk.Client.EmuHawk public string CorePath { get { return token.CorePath; } set { token.CorePath = value; } } } - class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro + public class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro { //you might think ideally we'd fetch the libretro core name from the core info inside it //but that would involve spinning up excess libretro core instances, which probably isnt good for stability, no matter how much we wish otherwise, not to mention slow. @@ -140,7 +140,7 @@ namespace BizHawk.Client.EmuHawk public string CorePath { get { return _corePath; } set { _corePath = value; } } } - class OpenAdvanced_OpenRom : IOpenAdvanced + public class OpenAdvanced_OpenRom : IOpenAdvanced { public OpenAdvanced_OpenRom() {} diff --git a/BizHawk.Client.Common/plugins/IPluginAPI.cs b/BizHawk.Client.Common/plugins/IPluginAPI.cs deleted file mode 100644 index 175df3af92..0000000000 --- a/BizHawk.Client.Common/plugins/IPluginAPI.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace BizHawk.Client.Common -{ - public interface IPluginAPI - { - EmulatorPluginLibrary EmuLib { get; } - GameInfoPluginLibrary GameInfoLib { get; } - GUIDrawPluginBase GUILib { get; } - JoypadPluginLibrary JoypadLib { get; } - MemoryPluginLibrary MemLib { get; } - MemoryEventsPluginLibrary MemEventsLib { get; } - MemorySavestatePluginLibrary MemStateLib { get; } - MoviePluginLibrary MovieLib { get; } - SQLPluginLibrary SQLLib { get; } - UserDataPluginLibrary UserDataLib { get; } - Dictionary Libraries { get; } - } -} diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs b/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs deleted file mode 100644 index ac9552d9cd..0000000000 --- a/BizHawk.Client.Common/plugins/PluginLibrary.Movie.cs +++ /dev/null @@ -1,263 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace BizHawk.Client.Common -{ - public sealed class MoviePluginLibrary : PluginLibraryBase - { - public MoviePluginLibrary() : base() - { } - - [LuaMethodExample("if ( movie.startsfromsavestate( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a savestate-anchored movie\" );\r\nend;")] - [LuaMethod("startsfromsavestate", "Returns whether or not the movie is a savestate-anchored movie")] - public bool StartsFromSavestate() - { - return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSavestate; - } - - [LuaMethodExample("if ( movie.startsfromsaveram( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a saveram-anchored movie\" );\r\nend;")] - [LuaMethod("startsfromsaveram", "Returns whether or not the movie is a saveram-anchored movie")] - public bool StartsFromSaveram() - { - return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSaveRam; - } - - [LuaMethodExample("local stmovfil = movie.filename( );")] - [LuaMethod("filename", "Returns the file name including path of the currently loaded movie")] - public static string Filename() - { - return Global.MovieSession.Movie.Filename; - } - - [LuaMethodExample("local nlmovget = movie.getinput( 500 );")] - [LuaMethod("getinput", "Returns a table of buttons pressed on a given frame of the loaded movie")] - public Dictionary GetInput(int frame) - { - if (!Global.MovieSession.Movie.IsActive) - { - Console.WriteLine("No movie loaded"); - return null; - } - - var input = new Dictionary(); - var adapter = Global.MovieSession.Movie.GetInputState(frame); - - if (adapter == null) - { - Console.WriteLine("Can't get input of the last frame of the movie. Use the previous frame"); - return null; - } - - foreach (var button in adapter.Definition.BoolButtons) - { - input[button] = adapter.IsPressed(button); - } - - foreach (var button in adapter.Definition.FloatControls) - { - input[button] = adapter.GetFloat(button); - } - - return input; - } - - [LuaMethodExample("local stmovget = movie.getinputasmnemonic( 500 );")] - [LuaMethod("getinputasmnemonic", "Returns the input of a given frame of the loaded movie in a raw inputlog string")] - public string GetInputAsMnemonic(int frame) - { - if (Global.MovieSession.Movie.IsActive && frame < Global.MovieSession.Movie.InputLogLength) - { - var lg = Global.MovieSession.LogGeneratorInstance(); - lg.SetSource(Global.MovieSession.Movie.GetInputState(frame)); - return lg.GenerateLogEntry(); - } - - return ""; - } - - [LuaMethodExample("if ( movie.getreadonly( ) ) then\r\n\tconsole.log( \"Returns true if the movie is in read-only mode, false if in read+write\" );\r\nend;")] - [LuaMethod("getreadonly", "Returns true if the movie is in read-only mode, false if in read+write")] - public static bool GetReadOnly() - { - return Global.MovieSession.ReadOnly; - } - - [LuaMethodExample("local ulmovget = movie.getrerecordcount();")] - [LuaMethod("getrerecordcount", "Gets the rerecord count of the current movie.")] - public static ulong GetRerecordCount() - { - return Global.MovieSession.Movie.Rerecords; - } - - [LuaMethodExample("if ( movie.getrerecordcounting( ) ) then\r\n\tconsole.log( \"Returns whether or not the current movie is incrementing rerecords on loadstate\" );\r\nend;")] - [LuaMethod("getrerecordcounting", "Returns whether or not the current movie is incrementing rerecords on loadstate")] - public static bool GetRerecordCounting() - { - return Global.MovieSession.Movie.IsCountingRerecords; - } - - [LuaMethodExample("if ( movie.isloaded( ) ) then\r\n\tconsole.log( \"Returns true if a movie is loaded in memory ( play, record, or finished modes ), false if not ( inactive mode )\" );\r\nend;")] - [LuaMethod("isloaded", "Returns true if a movie is loaded in memory (play, record, or finished modes), false if not (inactive mode)")] - public static bool IsLoaded() - { - return Global.MovieSession.Movie.IsActive; - } - - [LuaMethodExample("local domovlen = movie.length( );")] - [LuaMethod("length", "Returns the total number of frames of the loaded movie")] - public static double Length() - { - return Global.MovieSession.Movie.FrameCount; - } - - [LuaMethodExample("local stmovmod = movie.mode( );")] - [LuaMethod("mode", "Returns the mode of the current movie. Possible modes: \"PLAY\", \"RECORD\", \"FINISHED\", \"INACTIVE\"")] - public static string Mode() - { - if (Global.MovieSession.Movie.IsFinished) - { - return "FINISHED"; - } - - if (Global.MovieSession.Movie.IsPlaying) - { - return "PLAY"; - } - - if (Global.MovieSession.Movie.IsRecording) - { - return "RECORD"; - } - - return "INACTIVE"; - } - - [LuaMethodExample("movie.save( \"C:\\moviename.ext\" );")] - [LuaMethod("save", "Saves the current movie to the disc. If the filename is provided (no extension or path needed), the movie is saved under the specified name to the current movie directory. The filename may contain a subdirectory, it will be created if it doesn't exist. Existing files won't get overwritten.")] - public void Save(string filename = "") - { - if (!Global.MovieSession.Movie.IsActive) - { - return; - } - - if (!string.IsNullOrEmpty(filename)) - { - filename += "." + Global.MovieSession.Movie.PreferredExtension; - var test = new FileInfo(filename); - if (test.Exists) - { - Console.WriteLine($"File {filename} already exists, will not overwrite"); - return; - } - - Global.MovieSession.Movie.Filename = filename; - } - - Global.MovieSession.Movie.Save(); - } - - [LuaMethodExample("movie.setreadonly( false );")] - [LuaMethod("setreadonly", "Sets the read-only state to the given value. true for read only, false for read+write")] - public static void SetReadOnly(bool readOnly) - { - Global.MovieSession.ReadOnly = readOnly; - } - - [LuaMethodExample("movie.setrerecordcount( 20.0 );")] - [LuaMethod("setrerecordcount", "Sets the rerecord count of the current movie.")] - public static void SetRerecordCount(double count) - { - // Lua numbers are always double, integer precision holds up - // to 53 bits, so throw an error if it's bigger than that. - const double PrecisionLimit = 9007199254740992d; - - if (count > PrecisionLimit) - { - throw new Exception("Rerecord count exceeds Lua integer precision."); - } - - Global.MovieSession.Movie.Rerecords = (ulong)count; - } - - [LuaMethodExample("movie.setrerecordcounting( true );")] - [LuaMethod("setrerecordcounting", "Sets whether or not the current movie will increment the rerecord counter on loadstate")] - public static void SetRerecordCounting(bool counting) - { - Global.MovieSession.Movie.IsCountingRerecords = counting; - } - - [LuaMethodExample("movie.stop( );")] - [LuaMethod("stop", "Stops the current movie")] - public static void Stop() - { - Global.MovieSession.Movie.Stop(); - } - - [LuaMethodExample("local domovget = movie.getfps( );")] - [LuaMethod("getfps", "If a movie is loaded, gets the frames per second used by the movie to determine the movie length time")] - public static double GetFps() - { - if (Global.MovieSession.Movie.IsActive) - { - var movie = Global.MovieSession.Movie; - var system = movie.HeaderEntries[HeaderKeys.PLATFORM]; - var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) && - movie.HeaderEntries[HeaderKeys.PAL] == "1"; - - return new PlatformFrameRates()[system, pal]; - } - - return 0.0; - } - - [LuaMethodExample("local nlmovget = movie.getheader( );")] - [LuaMethod("getheader", "If a movie is active, will return the movie header as a lua table")] - public Dictionary GetHeader() - { - var table = new Dictionary(); - if (Global.MovieSession.Movie.IsActive) - { - foreach (var kvp in Global.MovieSession.Movie.HeaderEntries) - { - table[kvp.Key] = kvp.Value; - } - } - - return table; - } - - [LuaMethodExample("local nlmovget = movie.getcomments( );")] - [LuaMethod("getcomments", "If a movie is active, will return the movie comments as a lua table")] - public List GetComments() - { - var list = new List(Global.MovieSession.Movie.Comments.Count); - if (Global.MovieSession.Movie.IsActive) - { - for (int i = 0; i < Global.MovieSession.Movie.Comments.Count; i++) - { - list[i] = Global.MovieSession.Movie.Comments[i]; - } - } - - return list; - } - - [LuaMethodExample("local nlmovget = movie.getsubtitles( );")] - [LuaMethod("getsubtitles", "If a movie is active, will return the movie subtitles as a lua table")] - public List GetSubtitles() - { - var list = new List(Global.MovieSession.Movie.Subtitles.Count); - if (Global.MovieSession.Movie.IsActive) - { - for (int i = 0; i < Global.MovieSession.Movie.Subtitles.Count; i++) - { - list[i] = Global.MovieSession.Movie.Subtitles[i].ToString(); - } - } - - return list; - } - } -} diff --git a/BizHawk.Client.Common/plugins/PluginLibraryBase.cs b/BizHawk.Client.Common/plugins/PluginLibraryBase.cs deleted file mode 100644 index 17485c7103..0000000000 --- a/BizHawk.Client.Common/plugins/PluginLibraryBase.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Drawing; - -namespace BizHawk.Client.Common -{ - public abstract class PluginLibraryBase - { - protected PluginLibraryBase() { } - - protected static Color? ToColor(object o) - { - if (o == null) - { - return null; - } - - if (o.GetType() == typeof(double)) - { - return Color.FromArgb((int)(long)(double)o); - } - - if (o.GetType() == typeof(string)) - { - return Color.FromName(o.ToString()); - } - - return null; - } - } -} diff --git a/BizHawk.Client.EmuHawk/Api/ApiContainer.cs b/BizHawk.Client.EmuHawk/Api/ApiContainer.cs new file mode 100644 index 0000000000..6a7b7102a3 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Api/ApiContainer.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; + +using BizHawk.Client.ApiHawk; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class ApiContainer : IApiContainer + { + public IComm Comm => (IComm)Libraries[typeof(CommApi)]; + public IEmu Emu => (IEmu)Libraries[typeof(EmuApi)]; + public IGameInfo GameInfo => (IGameInfo)Libraries[typeof(GameInfoApi)]; + public IGui Gui => (IGui)Libraries[typeof(GuiApi)]; + public IInput Input => (IInput)Libraries[typeof(InputApi)]; + public IJoypad Joypad => (IJoypad)Libraries[typeof(JoypadApi)]; + public IMem Mem => (IMem)Libraries[typeof(MemApi)]; + public IMemEvents MemEvents => (IMemEvents)Libraries[typeof(MemEventsApi)]; + public IMemorySaveState MemorySaveState => (IMemorySaveState)Libraries[typeof(MemorySaveStateApi)]; + public IMovie Movie => (IMovie)Libraries[typeof(MovieApi)]; + public ISaveState SaveState => (ISaveState)Libraries[typeof(SaveStateApi)]; + public ISql Sql => (ISql)Libraries[typeof(SqlApi)]; + public ITool Tool => (ITool)Libraries[typeof(ToolApi)]; + public IUserData UserData => (IUserData)Libraries[typeof(UserDataApi)]; + public Dictionary Libraries { get; set; } + public ApiContainer(Dictionary libs) + { + Libraries = libs; + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs b/BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs similarity index 51% rename from BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs rename to BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs index e7ed248bfb..8764258e3d 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Example/Ecco2AssistantPlugin.cs +++ b/BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs @@ -4,13 +4,31 @@ using System.Globalization; using System.Drawing; using System.Linq; -using BizHawk.Client.Common; +using BizHawk.Client.ApiHawk; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; namespace BizHawk.Client.EmuHawk { public sealed class Ecco2AssistantPlugin : PluginBase { + [RequiredApi] + private IMem Mem {get; set;} + + [RequiredApi] + private IGui Gui { get; set; } + + [RequiredApi] + private IJoypad Joy { get; set; } + + [RequiredApi] + private IEmu Emu { get; set; } + + [RequiredApi] + private IGameInfo GI { get; set; } + + [RequiredApi] + private IMemorySaveState MemSS { get; set; } + public override string Name => "Ecco 2 Assistant"; public override string Description => "Displays a hud with hitboxes, etc. Assists with maintaining maximum speed."; @@ -36,7 +54,6 @@ namespace BizHawk.Client.EmuHawk private int _destY = 0; private int _snapPast = 0; private string _rowStateGuid = string.Empty; - private EmuHawkPluginLibrary _clientLib; private Color[] _turnSignalColors = { Color.FromArgb(_signalAlpha, 127, 127, 0), @@ -53,7 +70,7 @@ namespace BizHawk.Client.EmuHawk { if (refresh) { - _rseed = (int)(_api.MemLib.ReadU16(0xFFE2F8)); + _rseed = (int)(Mem.ReadU16(0xFFE2F8)); } bool odd = (_rseed & 1) != 0; _rseed >>= 1; @@ -73,7 +90,7 @@ namespace BizHawk.Client.EmuHawk }; Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(rhombus, color, fillColor); + Gui.DrawPolygon(rhombus, color, fillColor); } private void DrawEccoRhomb_scaled(int x, int y, int width, int height, int rscale, int bscale, int lscale, int tscale, Color color, int fillAlpha = 63) { @@ -85,7 +102,7 @@ namespace BizHawk.Client.EmuHawk }; Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(rhombus, color, fillColor); + Gui.DrawPolygon(rhombus, color, fillColor); } private void DrawEccoOct(int x, int y, int r, Color color, int fillAlpha = 63) { @@ -102,7 +119,7 @@ namespace BizHawk.Client.EmuHawk }; Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(octagon, color, fillColor); + Gui.DrawPolygon(octagon, color, fillColor); } private void DrawEccoOct_scaled(int x, int y, int xscale, int yscale, int r, Color color, int fillAlpha = 63) { @@ -123,7 +140,7 @@ namespace BizHawk.Client.EmuHawk }; Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(octagon, color, fillColor); + Gui.DrawPolygon(octagon, color, fillColor); } private Point? Intersection(Point start1, Point end1, Point start2, Point end2) { @@ -203,7 +220,7 @@ namespace BizHawk.Client.EmuHawk my /= finalShape.ToArray().Length; Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(finalShape.OrderBy(p => Math.Atan2(p.Y - my, p.X - mX)).ToArray(), color, fillColor); + Gui.DrawPolygon(finalShape.OrderBy(p => Math.Atan2(p.Y - my, p.X - mX)).ToArray(), color, fillColor); } private void DrawEccoTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color, int fillAlpha = 63) { @@ -215,23 +232,23 @@ namespace BizHawk.Client.EmuHawk new Point(x3, y3) }; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawPolygon(triPoints, color, fillColor); + Gui.DrawPolygon(triPoints, color, fillColor); } private void DrawBoxMWH(int x, int y, int w, int h, Color color, int fillAlpha = 63) { Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawRectangle(x - w, y - h, w << 1, h << 1, color, fillColor); + Gui.DrawRectangle(x - w, y - h, w << 1, h << 1, color, fillColor); } private void DrawBox(int x, int y, int x2, int y2, Color color, int fillAlpha = 63) { Color? fillColor = null; if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - _api.GUILib.DrawBox(x, y, x2, y2, color, fillColor); + Gui.DrawBox(x, y, x2, y2, color, fillColor); } private void Print_Text(string message, int x, int y, Color color) { - _api.GUILib.DrawText(x, y, message, color, null); + Gui.DrawText(x, y, message, color, null); } private void PutText(string message, int x, int y, int xl, int yl, int xh, int yh, Color bg, Color fg) { @@ -253,24 +270,24 @@ namespace BizHawk.Client.EmuHawk private void TickerText(string message, Color? fg = null) { if (_dumpMap == 0) - _api.GUILib.Text(1, _tickerY, message, fg); + Gui.Text(1, _tickerY, message, fg); _tickerY += 16; } private void EccoDraw3D() { - int CamX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC) - _left; - int CamY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC) + _top; - int CamZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xC) + _top; - uint curObj = _api.MemLib.ReadU24(0xFFD4C1); + int CamX = (Mem.ReadS32(0xFFD5E0) >> 0xC) - _left; + int CamY = (Mem.ReadS32(0xFFD5E8) >> 0xC) + _top; + int CamZ = (Mem.ReadS32(0xFFD5E4) >> 0xC) + _top; + uint curObj = Mem.ReadU24(0xFFD4C1); while (curObj != 0) { - int Xpos = (_api.MemLib.ReadS32(curObj + 0x6) >> 0xC); - int Ypos = (_api.MemLib.ReadS32(curObj + 0xE) >> 0xC); - int Zpos = (_api.MemLib.ReadS32(curObj + 0xA) >> 0xC); + int Xpos = (Mem.ReadS32(curObj + 0x6) >> 0xC); + int Ypos = (Mem.ReadS32(curObj + 0xE) >> 0xC); + int Zpos = (Mem.ReadS32(curObj + 0xA) >> 0xC); int Xmid = 160 + (Xpos - CamX); int Ymid = 112 - (Ypos - CamY); int Zmid = _top + 112 - (Zpos - CamZ); - uint type = _api.MemLib.ReadU32(curObj + 0x5A); + uint type = Mem.ReadU32(curObj + 0x5A); int width, height, depth = height = width = 0; if (type == 0xD4AB8) // 3D poison Bubble { @@ -285,23 +302,23 @@ namespace BizHawk.Client.EmuHawk else if (type == 0xD817E)// 3D Ring { depth = 8; - if (_api.MemLib.ReadU32(0xFFB166) < 0x1800) depth = 4; + if (Mem.ReadU32(0xFFB166) < 0x1800) depth = 4; int radius = 32; width = radius; - DrawEccoOct(Xmid, Ymid, radius, (_api.MemLib.ReadS16(curObj + 0x62) == 0) ? Color.Orange : Color.Gray); + DrawEccoOct(Xmid, Ymid, radius, (Mem.ReadS16(curObj + 0x62) == 0) ? Color.Orange : Color.Gray); DrawBoxMWH(Xmid, Zmid, width, depth, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red, 0); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x6) / 4096.0:0.######}:{_api.MemLib.ReadS32(curObj + 0xE) / 4096.0:0.######}:{_api.MemLib.ReadS32(curObj + 0xA) / 2048.0:0.######}:{_api.MemLib.ReadByte(curObj + 0x72)}",Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x6) / 4096.0:0.######}:{Mem.ReadS32(curObj + 0xE) / 4096.0:0.######}:{Mem.ReadS32(curObj + 0xA) / 2048.0:0.######}:{Mem.ReadByte(curObj + 0x72)}",Color.Lime); } else if (type == 0xD49CC) // Vines collisions are based on draw position, which is a fucking pain in the ass to calculate { - int Xvel = (_api.MemLib.ReadS32(curObj + 0x3A) - _api.MemLib.ReadS32(curObj + 0x6)); - int Zvel = (_api.MemLib.ReadS32(curObj + 0x3E) - _api.MemLib.ReadS32(curObj + 0xA)); - int dx = _api.MemLib.ReadS32(0xFFD5E0) - _api.MemLib.ReadS32(0xFFD5C8) >> 3; - int dy = _api.MemLib.ReadS32(0xFFD5E8) - _api.MemLib.ReadS32(0xFFD600) >> 3; - int dz = _api.MemLib.ReadS32(0xFFD5E4) - _api.MemLib.ReadS32(0xFFD5CC); - var chargeCount = _api.MemLib.ReadByte(0xFFB19B); + int Xvel = (Mem.ReadS32(curObj + 0x3A) - Mem.ReadS32(curObj + 0x6)); + int Zvel = (Mem.ReadS32(curObj + 0x3E) - Mem.ReadS32(curObj + 0xA)); + int dx = Mem.ReadS32(0xFFD5E0) - Mem.ReadS32(0xFFD5C8) >> 3; + int dy = Mem.ReadS32(0xFFD5E8) - Mem.ReadS32(0xFFD600) >> 3; + int dz = Mem.ReadS32(0xFFD5E4) - Mem.ReadS32(0xFFD5CC); + var chargeCount = Mem.ReadByte(0xFFB19B); if (chargeCount == 0) { dz >>= 2; @@ -314,7 +331,7 @@ namespace BizHawk.Client.EmuHawk { dz >>= 4; } - if (_api.MemLib.ReadByte(curObj + 0x64) == 0) + if (Mem.ReadByte(curObj + 0x64) == 0) { Xvel >>= 0xA; Zvel >>= 9; @@ -324,21 +341,21 @@ namespace BizHawk.Client.EmuHawk Xvel >>= 9; Zvel >>= 0xA; } - Xvel += _api.MemLib.ReadS32(curObj + 0x2E); - Zvel += _api.MemLib.ReadS32(curObj + 0x32); - Zpos = (_api.MemLib.ReadS32(curObj + 0x26) + dz - _api.MemLib.ReadS32(0xFFD5E4)) >> 0xB; + Xvel += Mem.ReadS32(curObj + 0x2E); + Zvel += Mem.ReadS32(curObj + 0x32); + Zpos = (Mem.ReadS32(curObj + 0x26) + dz - Mem.ReadS32(0xFFD5E4)) >> 0xB; if ((Zpos < 0x600) && (Zpos > 0)) { Zpos += 0x20; int Xcur, Xmax, Ycur, Ymax; - int Zpos2 = (_api.MemLib.ReadS32(curObj + 0xA) + Zvel + dz - _api.MemLib.ReadS32(0xFFD5E4)) >> 0xB; + int Zpos2 = (Mem.ReadS32(curObj + 0xA) + Zvel + dz - Mem.ReadS32(0xFFD5E4)) >> 0xB; Zpos2 = Math.Max(Zpos2 + 0x20, 1); - if (_api.MemLib.ReadS16(curObj + 0x62) != 0) + if (Mem.ReadS16(curObj + 0x62) != 0) { - Xmid = _api.MemLib.ReadS32(curObj + 0x6) + dx + Xvel - _api.MemLib.ReadS32(0xFFD5E0); + Xmid = Mem.ReadS32(curObj + 0x6) + dx + Xvel - Mem.ReadS32(0xFFD5E0); if (Math.Abs(Xmid) > 0x400000) continue; - Xpos = _api.MemLib.ReadS32(curObj + 0x22) + dx - _api.MemLib.ReadS32(0xFFD5E0); + Xpos = Mem.ReadS32(curObj + 0x22) + dx - Mem.ReadS32(0xFFD5E0); if (Math.Abs(Xpos) > 0x400000) continue; Xcur = (Xmid << 2) / Zpos2 + (Xmid >> 5) + 0xA000 + (Xmid >> 5); @@ -349,9 +366,9 @@ namespace BizHawk.Client.EmuHawk Xcur = 0; Xmax = 256; } - Ymid = _api.MemLib.ReadS32(0xFFD5E8) + dy - _api.MemLib.ReadS32(curObj + 0xE); + Ymid = Mem.ReadS32(0xFFD5E8) + dy - Mem.ReadS32(curObj + 0xE); Ycur = ((Ymid << 3) / Zpos2) + 0x6000; - Ypos = _api.MemLib.ReadS32(0xFFD5E8) + dy - _api.MemLib.ReadS32(curObj + 0x2A); + Ypos = Mem.ReadS32(0xFFD5E8) + dy - Mem.ReadS32(curObj + 0x2A); Ymax = ((Ypos << 3) / Zpos) + 0x6000; dx = Xmax - Xcur; dy = Ymax - Ycur; @@ -423,8 +440,8 @@ namespace BizHawk.Client.EmuHawk } } } - Xcur += _api.MemLib.ReadS8(0x2CC8 + ang) << 6; - Ycur += _api.MemLib.ReadS8(0x2BC8 + ang) << 6; + Xcur += Mem.ReadS8(0x2CC8 + ang) << 6; + Ycur += Mem.ReadS8(0x2BC8 + ang) << 6; var dSml = Math.Abs(dx); var dBig = Math.Abs(dy); if (dBig < dSml) @@ -438,7 +455,7 @@ namespace BizHawk.Client.EmuHawk dx /= i; dy /= i; - Zmid = (_api.MemLib.ReadS32(curObj + 0xA) + _api.MemLib.ReadS32(curObj + 0x26)) >> 1; + Zmid = (Mem.ReadS32(curObj + 0xA) + Mem.ReadS32(curObj + 0x26)) >> 1; Zmid >>= 0xC; Zmid = 112 + _top - (Zmid - CamZ); do @@ -449,14 +466,14 @@ namespace BizHawk.Client.EmuHawk Xcur += dx; Ycur += dy; } while (i >= 0); - DrawBoxMWH((_api.MemLib.ReadS32(0xFFB1AA) >> 8) + _left, (_api.MemLib.ReadS32(0xFFB1AE) >> 8) + _top, 1, 1, Color.Lime, 0); + DrawBoxMWH((Mem.ReadS32(0xFFB1AA) >> 8) + _left, (Mem.ReadS32(0xFFB1AE) >> 8) + _top, 1, 1, Color.Lime, 0); } } else if ((type == 0xD3B40) || (type == 0xD3DB2)) // 3D Shark and Jellyfish { - width = (_api.MemLib.ReadS32(curObj + 0x12) >> 0xC); - height = (_api.MemLib.ReadS32(curObj + 0x1A) >> 0xC); - depth = (_api.MemLib.ReadS32(curObj + 0x16) >> 0xC); + width = (Mem.ReadS32(curObj + 0x12) >> 0xC); + height = (Mem.ReadS32(curObj + 0x1A) >> 0xC); + depth = (Mem.ReadS32(curObj + 0x16) >> 0xC); DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); DrawBoxMWH(Xmid, Zmid, width, depth, Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); @@ -502,7 +519,7 @@ namespace BizHawk.Client.EmuHawk DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red); } } - curObj = _api.MemLib.ReadU24(curObj+1); + curObj = Mem.ReadU24(curObj+1); } } private void EccoDrawBoxes() @@ -511,8 +528,8 @@ namespace BizHawk.Client.EmuHawk int Width2, Height2; //Ecco HP and Air int i = 0; - int HP = _api.MemLib.ReadS16(0xFFAA16) << 3; - int air = _api.MemLib.ReadS16(0xFFAA18); + int HP = Mem.ReadS16(0xFFAA16) << 3; + int air = Mem.ReadS16(0xFFAA18); Color color; int off = 0; for (int j = 0; j < air; j++) @@ -522,66 +539,66 @@ namespace BizHawk.Client.EmuHawk i++; off += 448; } color = Color.FromArgb(j >> 2, j >> 2, j >> 2); - _api.GUILib.DrawLine(_left - 32, j - off, _left - 17, j - off, color); + Gui.DrawLine(_left - 32, j - off, _left - 17, j - off, color); } for (int j = 0; j < HP; j += 8) { color = Color.FromArgb(Math.Max(0x38 - (j >> 3),0), 0, Math.Min(j >> 1,255)); - _api.GUILib.DrawRectangle(_left - 16, j, 15, 7, color, color); + Gui.DrawRectangle(_left - 16, j, 15, 7, color, color); } //Asterite - uint type = _api.MemLib.ReadU32(0xFFD440); + uint type = Mem.ReadU32(0xFFD440); uint curObj = 0; int Xpos, Xpos2, Ypos, Ypos2, Xmid, Ymid, X, X2, Y, Y2; Xpos = Ypos = Xpos2 = Ypos2 = Xmid = Ymid = X = X2 = Y = Y2 = 0; if (type == 0xB119A) { - curObj = _api.MemLib.ReadU24(_api.MemLib.ReadU24(0xFFD429)+5); + curObj = Mem.ReadU24(Mem.ReadU24(0xFFD429)+5); while (curObj != 0) { - Xpos = _api.MemLib.ReadS16(curObj + 0x3C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x40); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x3C); + Xpos2 = Mem.ReadS16(curObj + 0x24); + Ypos = Mem.ReadS16(curObj + 0x40); + Ypos2 = Mem.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; - if (_api.MemLib.ReadU8(curObj + 0x71) != 0) + if (Mem.ReadU8(curObj + 0x71) != 0) { DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); } - curObj = _api.MemLib.ReadU24(curObj + 5); + curObj = Mem.ReadU24(curObj + 5); } - if ((_api.MemLib.ReadU8(0xFFA7D0) == 30)) + if ((Mem.ReadU8(0xFFA7D0) == 30)) { - curObj = _api.MemLib.ReadU24(0xFFD425); - if ((curObj != 0) && (_api.MemLib.ReadU32(curObj + 8) != 0)) + curObj = Mem.ReadU24(0xFFD425); + if ((curObj != 0) && (Mem.ReadU32(curObj + 8) != 0)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; + Ypos = Mem.ReadS16(curObj + 0x20) - _camY; DrawEccoOct(Xpos, Ypos, 20, Color.Orange); } } } else if (type == 0xB2CB8) { - curObj = _api.MemLib.ReadU24(_api.MemLib.ReadU24(0xFFD429) + 5); + curObj = Mem.ReadU24(Mem.ReadU24(0xFFD429) + 5); while (curObj != 0) { - Xpos = _api.MemLib.ReadS16(curObj + 0x3C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x24); - Ypos = _api.MemLib.ReadS16(curObj + 0x40); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x3C); + Xpos2 = Mem.ReadS16(curObj + 0x24); + Ypos = Mem.ReadS16(curObj + 0x40); + Ypos2 = Mem.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; - if (_api.MemLib.ReadU8(curObj + 0x71) != 0) + if (Mem.ReadU8(curObj + 0x71) != 0) { - if (_api.MemLib.ReadByte(0xFFA7D0) != 0x1F) + if (Mem.ReadByte(0xFFA7D0) != 0x1F) { DrawEccoOct(Xpos, Ypos, 40, Color.Lime); DrawEccoOct(Xpos2, Ypos2, 40, Color.Lime); @@ -589,23 +606,23 @@ namespace BizHawk.Client.EmuHawk DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); } - curObj = _api.MemLib.ReadU24(curObj + 5); + curObj = Mem.ReadU24(curObj + 5); } } //aqua tubes - curObj = _api.MemLib.ReadU24(0xFFCFC5); + curObj = Mem.ReadU24(0xFFCFC5); while (curObj != 0) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2= _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2= Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2= Mem.ReadS16(curObj + 0x38); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; // displayed = false; - type = _api.MemLib.ReadU8(curObj + 0x7E); + type = Mem.ReadU8(curObj + 0x7E); switch (type) { case 0x15: @@ -639,7 +656,7 @@ namespace BizHawk.Client.EmuHawk new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), new Point(Xpos2, Ymid) }; - _api.GUILib.DrawPolygon(trapPoints, Color.Purple, Color.FromArgb(63, Color.Purple)); + Gui.DrawPolygon(trapPoints, Color.Purple, Color.FromArgb(63, Color.Purple)); break; default: DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Purple); @@ -647,22 +664,22 @@ namespace BizHawk.Client.EmuHawk PutText(type.ToString("X2"), Xmid, Ymid, 1, 1, -1, -1, Color.Red, Color.Blue); break; } - curObj = _api.MemLib.ReadU24(curObj+1); + curObj = Mem.ReadU24(curObj+1); } //walls - curObj = _api.MemLib.ReadU24(0xFFCFC1); + curObj = Mem.ReadU24(0xFFCFC1); while (curObj != 0) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24); - Xmid = _api.MemLib.ReadS16(curObj + 0x28); - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2= _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2= _api.MemLib.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS16(curObj + 0x24); + Xmid = Mem.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2= Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2= Mem.ReadS16(curObj + 0x38); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - int colltype = _api.MemLib.ReadS8(curObj + 0x7E); + int colltype = Mem.ReadS8(curObj + 0x7E); switch (colltype) { case 0x10: @@ -674,25 +691,25 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Xpos2 = Xmid; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.PowderBlue); + Gui.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.PowderBlue); break; case 0x12: Xmid = (Xpos + Xpos2) >> 1; Xpos = Xmid; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos, Ypos2, Color.PowderBlue); + Gui.DrawLine(Xpos, Ypos, Xpos, Ypos2, Color.PowderBlue); break; case 0x13: Ymid = (Ypos + Ypos2) >> 1; Ypos = Ymid; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.PowderBlue); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.PowderBlue); break; case 0x14: Ymid = (Ypos + Ypos2) >> 1; Ypos2 = Ymid; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.PowderBlue); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.PowderBlue); break; case 0x15: case 0x16: @@ -702,7 +719,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); + Gui.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); break; case 0x1A: case 0x1B: @@ -712,7 +729,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); + Gui.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); break; case 0x1F: case 0x20: @@ -722,7 +739,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63,Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); + Gui.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); break; case 0x24: case 0x25: @@ -732,17 +749,17 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63,Color.Yellow)); - _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); + Gui.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); break; case 0x29: DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - _api.GUILib.DrawLine(Xpos , Ypos, Xpos , Ypos2, Color.Black); - _api.GUILib.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.Black); + Gui.DrawLine(Xpos , Ypos, Xpos , Ypos2, Color.Black); + Gui.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.Black); break; case 0x2A: DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); break; case 0x2B: Xmid = (Xpos + Xpos2) >> 1; @@ -754,45 +771,45 @@ namespace BizHawk.Client.EmuHawk new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), new Point(Xpos2, Ymid) }; - _api.GUILib.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); - //_api.GUILib.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.Yellow); + Gui.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); + //Gui.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.Yellow); break; default: - DrawEccoRhomb_scaled(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); + DrawEccoRhomb_scaled(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); break; } - curObj = _api.MemLib.ReadU24(curObj+1); + curObj = Mem.ReadU24(curObj+1); } //inanimate objects - curObj = _api.MemLib.ReadU24(0xFFCFBD); + curObj = Mem.ReadU24(0xFFCFBD); while (curObj != 0) { - type = _api.MemLib.ReadU32(curObj + 0xC); - int colltype = _api.MemLib.ReadS8(curObj + 0x7E); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - int Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - int Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + type = Mem.ReadU32(curObj + 0xC); + int colltype = Mem.ReadS8(curObj + 0x7E); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + int Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + int Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; if (type == 0x9CE3A) //Remnant Stars { - uint subObj = _api.MemLib.ReadU24(curObj + 0x5); - uint anim = _api.MemLib.ReadU16(curObj + 0x6C); + uint subObj = Mem.ReadU24(curObj + 0x5); + uint anim = Mem.ReadU16(curObj + 0x6C); if ((anim <= 7) && (subObj == 0xFFA9D4)) { DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); - PutText($"{((7 - anim) * 4) - ((_api.MemLib.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Lime, Color.Blue); + PutText($"{((7 - anim) * 4) - ((Mem.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Lime, Color.Blue); } } else if ((type == 0x9CC06) || (type == 0x9CA10)) { - Xvec = ((_api.MemLib.ReadS32(curObj + 0x24) + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((_api.MemLib.ReadS32(curObj + 0x28) + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xvec = ((Mem.ReadS32(curObj + 0x24) + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Mem.ReadS32(curObj + 0x28) + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; } else if (type == 0x9B5D8) { @@ -801,27 +818,27 @@ namespace BizHawk.Client.EmuHawk } else if (type == 0xC0152) // Vortex Future Vertical Gate { - Xvec = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Yvec = (_api.MemLib.ReadS32(curObj + 0x20) + _api.MemLib.ReadS32(curObj + 0x60) >> 16) - _camY; - _api.GUILib.DrawLine(Xmid, 0, Xmid, 448, Color.PowderBlue); + Xvec = Mem.ReadS16(curObj + 0x1C) - _camX; + Yvec = (Mem.ReadS32(curObj + 0x20) + Mem.ReadS32(curObj + 0x60) >> 16) - _camY; + Gui.DrawLine(Xmid, 0, Xmid, 448, Color.PowderBlue); DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); } else if (type == 0xC3330) // City Of Forever Horizontal Gate Slave { - Xvec = (_api.MemLib.ReadS32(curObj + 0x1C) + _api.MemLib.ReadS32(curObj + 0x5C) >> 16) - _camX; - Yvec = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + Xvec = (Mem.ReadS32(curObj + 0x1C) + Mem.ReadS32(curObj + 0x5C) >> 16) - _camX; + Yvec = Mem.ReadS16(curObj + 0x20) - _camY; DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); } else if (type == 0xC35B0) // City Of Forever Horizontal Gate Master { - var mode = _api.MemLib.ReadByte(curObj + 0x15); + var mode = Mem.ReadByte(curObj + 0x15); var tmpx = Xpos; - Xpos = _api.MemLib.ReadS32(curObj + 0x1C); - Xvec = (Xpos + _api.MemLib.ReadS32(curObj + 0x5C) >> 16) - _camX; + Xpos = Mem.ReadS32(curObj + 0x1C); + Xvec = (Xpos + Mem.ReadS32(curObj + 0x5C) >> 16) - _camX; Xpos >>= 16; Xpos -= _camX; - Yvec = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + Yvec = Mem.ReadS16(curObj + 0x20) - _camY; if ((mode == 1) || (mode == 3)) { DrawEccoOct(Xpos, Yvec, 128, Color.Orange); @@ -832,35 +849,35 @@ namespace BizHawk.Client.EmuHawk } else if (type == 0xC343A) // City Of Forever Vertical Gate { - var mode = _api.MemLib.ReadByte(curObj + 0x15); + var mode = Mem.ReadByte(curObj + 0x15); if ((mode == 1) || (mode == 3)) { DrawEccoOct(Xmid, Ymid, 128, Color.Orange); } - Xvec = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Yvec = (_api.MemLib.ReadS32(curObj + 0x20) + _api.MemLib.ReadS32(curObj + 0x60) >> 16) - _camY; + Xvec = Mem.ReadS16(curObj + 0x1C) - _camX; + Yvec = (Mem.ReadS32(curObj + 0x20) + Mem.ReadS32(curObj + 0x60) >> 16) - _camY; DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); } else if (type == 0xA579A) // Antigrav Ball { - DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x4C), (_api.MemLib.ReadU16(0xFFA7C8) & 7) == 7 ? Color.Blue : Color.Gray); + DrawEccoOct(Xmid, Ymid, Mem.ReadS16(curObj + 0x4C), (Mem.ReadU16(0xFFA7C8) & 7) == 7 ? Color.Blue : Color.Gray); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); Xpos = Ypos = Xpos2 = Ypos2 = _camX - 128; } else if (type == 0xDF4E2) // Moray Abyss Conch Shell { - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; - DrawBox(Xpos - 96, 0 - _camY, Xpos + 96, _api.MemLib.ReadS16(0xFFA7AC) - _camY - 64, Color.Orange, 0); - var mode = _api.MemLib.ReadByte(curObj + 0x15); - var modeTimer = _api.MemLib.ReadS16(curObj + 0x6E); - var Xvel1 = _api.MemLib.ReadS32(curObj + 0x54) / 65536.0; - var Yvel1 = _api.MemLib.ReadS32(curObj + 0x58) / 65536.0; - var Xvel2 = _api.MemLib.ReadS32(curObj + 0x5C) / 65536.0; - var Yvel2 = _api.MemLib.ReadS32(curObj + 0x60) / 65536.0; - TickerText($"{mode}:{modeTimer}:{_api.MemLib.ReadS16(0xFFA7AC) - 64 - Ymid - _camY}", Color.Red); + Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; + Ypos = Mem.ReadS16(curObj + 0x20) - _camY; + DrawBox(Xpos - 96, 0 - _camY, Xpos + 96, Mem.ReadS16(0xFFA7AC) - _camY - 64, Color.Orange, 0); + var mode = Mem.ReadByte(curObj + 0x15); + var modeTimer = Mem.ReadS16(curObj + 0x6E); + var Xvel1 = Mem.ReadS32(curObj + 0x54) / 65536.0; + var Yvel1 = Mem.ReadS32(curObj + 0x58) / 65536.0; + var Xvel2 = Mem.ReadS32(curObj + 0x5C) / 65536.0; + var Yvel2 = Mem.ReadS32(curObj + 0x60) / 65536.0; + TickerText($"{mode}:{modeTimer}:{Mem.ReadS16(0xFFA7AC) - 64 - Ymid - _camY}", Color.Red); TickerText($"{Xvel1:0.######}:{Yvel1:0.######}", Color.Red); TickerText($"{Xvel2:0.######}:{Yvel2:0.######}", Color.Red); TickerText($"{Xvel1 + Xvel2:0.######}:{Yvel1 + Yvel2:0.######}", Color.Red); @@ -882,8 +899,8 @@ namespace BizHawk.Client.EmuHawk break; case 1: DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Orange, 0); - Xpos2 = _api.MemLib.ReadS32(0xFFAA1A) - _api.MemLib.ReadS32(curObj + 0x24); - Ypos2 = _api.MemLib.ReadS32(0xFFAA1E) - _api.MemLib.ReadS32(curObj + 0x28); + Xpos2 = Mem.ReadS32(0xFFAA1A) - Mem.ReadS32(curObj + 0x24); + Ypos2 = Mem.ReadS32(0xFFAA1E) - Mem.ReadS32(curObj + 0x28); var dSml = Math.Abs(Xpos2); var dBig = Math.Abs(Ypos2); if (dBig < dSml) @@ -895,11 +912,11 @@ namespace BizHawk.Client.EmuHawk var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; Xpos2 = (int)(Xpos2 * (256.0 / (rad+1))) >> 20; Ypos2 = (int)(Ypos2 * (256.0 / (rad+1))) >> 20; - _api.GUILib.DrawLine(Xmid, Ymid, Xmid + Xpos2, Ymid + Ypos2, Color.Gray); + Gui.DrawLine(Xmid, Ymid, Xmid + Xpos2, Ymid + Ypos2, Color.Gray); TickerText($"{Xpos2 / 512.0:0.######}:{Ypos2 / 512.0:0.######}", Color.Red); break; case 2: - TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); + TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); break; } } @@ -908,10 +925,10 @@ namespace BizHawk.Client.EmuHawk || (type == 0xA6C4A) || (type == 0xAB65A) || (type == 0x9F2EC)) { } else { - PutText($"{type:X5}:{_api.MemLib.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.Lime, Color.Blue); + PutText($"{type:X5}:{Mem.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.Lime, Color.Blue); PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.Lime, Color.Blue); } - colltype = _api.MemLib.ReadS8(curObj + 0x7E); + colltype = Mem.ReadS8(curObj + 0x7E); switch (colltype) { case 0x10: @@ -947,7 +964,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); + Gui.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); break; case 0x1A: case 0x1B: @@ -957,7 +974,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); + Gui.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); break; case 0x1F: case 0x20: @@ -967,7 +984,7 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); + Gui.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); break; case 0x24: case 0x25: @@ -977,12 +994,12 @@ namespace BizHawk.Client.EmuHawk Xmid = (Xpos + Xpos2) >> 1; Ymid = (Ypos + Ypos2) >> 1; DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - _api.GUILib.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); + Gui.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); break; case 0x2A: DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); break; case 0x2B: Xmid = (Xpos + Xpos2) >> 1; @@ -994,70 +1011,70 @@ namespace BizHawk.Client.EmuHawk new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), new Point(Xpos2, Ymid) }; - _api.GUILib.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); + Gui.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); break; case 0x2C: break; default: - DrawEccoRhomb_scaled(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); + DrawEccoRhomb_scaled(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); break; } - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - curObj = _api.MemLib.ReadU24(curObj+1); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + curObj = Mem.ReadU24(curObj+1); } //animate objects if (_mode == Modes.Ecco2) - curObj = _api.MemLib.ReadU24(0xFFCFB9); + curObj = Mem.ReadU24(0xFFCFB9); else - curObj = _api.MemLib.ReadU24(0xFFD829); + curObj = Mem.ReadU24(0xFFD829); while (curObj != 0) { type = 0; switch (_mode) { case Modes.Ecco2: { - uint flags = _api.MemLib.ReadU16(curObj + 0x10); + uint flags = Mem.ReadU16(curObj + 0x10); int Xvec = 0; int Yvec = 0; //if ((flags & 0x2000) || !(flags & 2)); - HP = _api.MemLib.ReadS8(curObj + 0x7B); - type = _api.MemLib.ReadU32(curObj + 0xC); + HP = Mem.ReadS8(curObj + 0x7B); + type = Mem.ReadU32(curObj + 0xC); if ((type == 0xA1FE6) || (type == 0xA208E) // Chain link creatures such as vortex worm, magic arm, etc || (type == 0xA2288) || (type == 0xA27A4) || (type == 0xA2BB0) || (type == 0xA2C50)) { uint subObj = curObj; while (subObj != 0) { - Xpos = _api.MemLib.ReadS32(subObj + 0x24); - Ypos = _api.MemLib.ReadS32(subObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(subObj + 0x24); + Ypos = Mem.ReadS32(subObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - if (_api.MemLib.ReadS16(subObj + 0x44) == _api.MemLib.ReadS16(subObj + 0x48)) + if (Mem.ReadS16(subObj + 0x44) == Mem.ReadS16(subObj + 0x48)) { - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Cyan, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Cyan, 0); } else { - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Lime, 0); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.Blue, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Lime, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.Blue, 0); } DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - subObj = _api.MemLib.ReadU24(subObj + 5); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + subObj = Mem.ReadU24(subObj + 5); } if (HP > 2) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); } } @@ -1069,43 +1086,43 @@ namespace BizHawk.Client.EmuHawk uint subObj = curObj; while (subObj != 0) { - Xpos = _api.MemLib.ReadS32(subObj + 0x24); - Ypos = _api.MemLib.ReadS32(subObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(subObj + 0x24); + Ypos = Mem.ReadS32(subObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - if (_api.MemLib.ReadS16(subObj + 0x44) == _api.MemLib.ReadS16(subObj + 0x48)) + if (Mem.ReadS16(subObj + 0x44) == Mem.ReadS16(subObj + 0x48)) { - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.White, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.White, 0); } else { - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x44), Color.Lime, 0); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(subObj + 0x48), Color.Magenta, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Lime, 0); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.FromArgb(255, 0, 127)); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.Magenta, 0); } DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); if (type == 0xBA66E) { DrawEccoOct(Xpos, Ypos, 32, Color.Blue, 16); if (subObj == curObj) { - var mode = _api.MemLib.ReadByte(subObj + 0x15); - TickerText($"{_api.MemLib.ReadByte(subObj + 0x14)}:{mode}:{_api.MemLib.ReadByte(subObj + 0x70)}", Color.Red); - TickerText($"{_api.MemLib.ReadS32(subObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); - TickerText($"{_api.MemLib.ReadS32(subObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x50) / 65536.0:0.######}", Color.Red); + var mode = Mem.ReadByte(subObj + 0x15); + TickerText($"{Mem.ReadByte(subObj + 0x14)}:{mode}:{Mem.ReadByte(subObj + 0x70)}", Color.Red); + TickerText($"{Mem.ReadS32(subObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); + TickerText($"{Mem.ReadS32(subObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x50) / 65536.0:0.######}", Color.Red); switch (mode) { case 0: case 2: case 4: - Xpos2 = _api.MemLib.ReadS32(0xFFAA22) - _api.MemLib.ReadS32(subObj + 0x24); - Ypos2 = _api.MemLib.ReadS32(0xFFAA26) - _api.MemLib.ReadS32(subObj + 0x28); + Xpos2 = Mem.ReadS32(0xFFAA22) - Mem.ReadS32(subObj + 0x24); + Ypos2 = Mem.ReadS32(0xFFAA26) - Mem.ReadS32(subObj + 0x28); var dSml = Math.Abs(Xpos2); var dBig = Math.Abs(Ypos2); if (dBig < dSml) @@ -1117,7 +1134,7 @@ namespace BizHawk.Client.EmuHawk var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; Xpos2 = (int)(Xpos2 * (256.0 / (rad + 1))) >> 20; Ypos2 = (int)(Ypos2 * (256.0 / (rad + 1))) >> 20; - _api.GUILib.DrawLine(Xpos, Ypos, Xpos + Xpos2, Ypos + Ypos2, Color.Red); + Gui.DrawLine(Xpos, Ypos, Xpos + Xpos2, Ypos + Ypos2, Color.Red); break; default: break; @@ -1125,13 +1142,13 @@ namespace BizHawk.Client.EmuHawk } } } - else if ((type == 0xBA52E) && (subObj == _api.MemLib.ReadU24(curObj + 0x1D))) + else if ((type == 0xBA52E) && (subObj == Mem.ReadU24(curObj + 0x1D))) { - DrawEccoOct(Xpos, Ypos, 32, (_api.MemLib.ReadByte(subObj + 0x70) == 0) ? Color.Blue : Color.Gray, 16); - var mode = _api.MemLib.ReadByte(curObj + 0x15); - TickerText($"{_api.MemLib.ReadByte(curObj + 0x14)}:{mode}:{_api.MemLib.ReadS16(curObj + 0x6E)}:{_api.MemLib.ReadByte(subObj + 0x70)}", Color.Red); - TickerText($"{_api.MemLib.ReadS32(subObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); + DrawEccoOct(Xpos, Ypos, 32, (Mem.ReadByte(subObj + 0x70) == 0) ? Color.Blue : Color.Gray, 16); + var mode = Mem.ReadByte(curObj + 0x15); + TickerText($"{Mem.ReadByte(curObj + 0x14)}:{mode}:{Mem.ReadS16(curObj + 0x6E)}:{Mem.ReadByte(subObj + 0x70)}", Color.Red); + TickerText($"{Mem.ReadS32(subObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); + TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); } else if (type == 0xE0988) { @@ -1139,44 +1156,44 @@ namespace BizHawk.Client.EmuHawk } if (HP > 2) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); } - subObj = _api.MemLib.ReadU24(subObj + 5); + subObj = Mem.ReadU24(subObj + 5); } } else if (type == 0xB7DF4) { - Xpos = _api.MemLib.ReadS32(curObj + 0x24); - Ypos = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(curObj + 0x24); + Ypos = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; DrawEccoOct(Xpos, Ypos, 26, Color.PowderBlue); DrawEccoOct(Xpos, Ypos, 26, Color.White); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec); } else if (type == 0xE47EE) { - uint subObj = _api.MemLib.ReadU24(curObj + 5); + uint subObj = Mem.ReadU24(curObj + 5); while (subObj != 0) { - Xpos = _api.MemLib.ReadS32(subObj + 0x1C); - Ypos = _api.MemLib.ReadS32(subObj + 0x20); - Xvec = ((Xpos + _api.MemLib.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(subObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(subObj + 0x1C); + Ypos = Mem.ReadS32(subObj + 0x20); + Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, ((_api.MemLib.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.White); - DrawEccoOct(Xpos, Ypos, ((_api.MemLib.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.Yellow, 0); + DrawEccoOct(Xpos, Ypos, ((Mem.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.White); + DrawEccoOct(Xpos, Ypos, ((Mem.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.Yellow, 0); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - subObj = _api.MemLib.ReadU24(subObj + 5); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + subObj = Mem.ReadU24(subObj + 5); } } else if (type == 0xDBE64) // Medusa Boss @@ -1185,21 +1202,21 @@ namespace BizHawk.Client.EmuHawk uint next; do { - next = _api.MemLib.ReadU24(subObj + 5); + next = Mem.ReadU24(subObj + 5); if (next != 0) subObj = next; } while (next != 0); - Xpos = _api.MemLib.ReadS16(subObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(subObj + 0x34); - Ypos = _api.MemLib.ReadS16(subObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(subObj + 0x38); + Xpos = Mem.ReadS16(subObj + 0x2C); + Xpos2 = Mem.ReadS16(subObj + 0x34); + Ypos = Mem.ReadS16(subObj + 0x30); + Ypos2 = Mem.ReadS16(subObj + 0x38); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; DrawEccoOct(Xpos, Ypos, 32, Color.Red); DrawEccoOct(Xpos2, Ypos2, 32, Color.Red); - Xpos = _api.MemLib.ReadS32(curObj + 0x24); - Ypos = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(curObj + 0x24); + Ypos = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; @@ -1212,86 +1229,86 @@ namespace BizHawk.Client.EmuHawk new Point(Xpos + octOff, Ypos - octOff), new Point(Xpos + 60, Ypos) }; - _api.GUILib.DrawPolygon(hemiOctPoints, Color.Cyan, Color.FromArgb(0x3F, Color.Cyan)); + Gui.DrawPolygon(hemiOctPoints, Color.Cyan, Color.FromArgb(0x3F, Color.Cyan)); for (int l = 0; l < 4; l++) { - _api.GUILib.DrawLine(hemiOctPoints[l].X, hemiOctPoints[l].Y, hemiOctPoints[l + 1].X, hemiOctPoints[l + 1].Y, Color.Cyan); + Gui.DrawLine(hemiOctPoints[l].X, hemiOctPoints[l].Y, hemiOctPoints[l + 1].X, hemiOctPoints[l + 1].Y, Color.Cyan); } DrawBoxMWH(Xpos, Ypos + 12, 52, 12, Color.Cyan); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); } else if (type == 0xDCEE0) // Globe Holder boss { uint subObj; - var mode = _api.MemLib.ReadByte(curObj + 0x15); + var mode = Mem.ReadByte(curObj + 0x15); if (mode < 4) { - subObj = _api.MemLib.ReadU24(curObj + 9); + subObj = Mem.ReadU24(curObj + 9); while (subObj != 0) { - Xmid = _api.MemLib.ReadS32(subObj + 0x24); - Ymid = _api.MemLib.ReadS32(subObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(subObj + 0x54) + _api.MemLib.ReadS32(subObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(subObj + 0x58) + _api.MemLib.ReadS32(subObj + 0x60)) >> 16) - _camY; + Xmid = Mem.ReadS32(subObj + 0x24); + Ymid = Mem.ReadS32(subObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(subObj + 0x54) + Mem.ReadS32(subObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(subObj + 0x58) + Mem.ReadS32(subObj + 0x60)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawEccoOct(Xmid, Ymid, 12, Color.Orange); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - var next = _api.MemLib.ReadU24(subObj + 9); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + var next = Mem.ReadU24(subObj + 9); if ((next == 0) && ((mode & 1) != 0)) { - DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(subObj + 0x3C), Color.Orange); + DrawEccoOct(Xmid, Ymid, Mem.ReadS16(subObj + 0x3C), Color.Orange); } - subObj = _api.MemLib.ReadU24(subObj + 9); + subObj = Mem.ReadU24(subObj + 9); } - subObj = _api.MemLib.ReadU24(curObj + 5); + subObj = Mem.ReadU24(curObj + 5); while (subObj != 0) { - Xmid = _api.MemLib.ReadS32(subObj + 0x24); - Ymid = _api.MemLib.ReadS32(subObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(subObj + 0x54) + _api.MemLib.ReadS32(subObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(subObj + 0x58) + _api.MemLib.ReadS32(subObj + 0x60)) >> 16) - _camY; + Xmid = Mem.ReadS32(subObj + 0x24); + Ymid = Mem.ReadS32(subObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(subObj + 0x54) + Mem.ReadS32(subObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(subObj + 0x58) + Mem.ReadS32(subObj + 0x60)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawEccoOct(Xmid, Ymid, 12, Color.Orange); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - var next = _api.MemLib.ReadU24(subObj + 5); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + var next = Mem.ReadU24(subObj + 5); if ((next == 0) && ((mode & 2) != 0)) { - DrawEccoOct(Xmid, Ymid, _api.MemLib.ReadS16(subObj + 0x3C), Color.Orange); + DrawEccoOct(Xmid, Ymid, Mem.ReadS16(subObj + 0x3C), Color.Orange); } - subObj = _api.MemLib.ReadU24(subObj + 5); + subObj = Mem.ReadU24(subObj + 5); } } - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - int Xtmp = _api.MemLib.ReadS32(curObj + 0x2C); - int Ytmp = _api.MemLib.ReadS32(curObj + 0x30); - int Xtmp2 = _api.MemLib.ReadS32(curObj + 0x34); - int Ytmp2 = _api.MemLib.ReadS32(curObj + 0x38); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + int Xtmp = Mem.ReadS32(curObj + 0x2C); + int Ytmp = Mem.ReadS32(curObj + 0x30); + int Xtmp2 = Mem.ReadS32(curObj + 0x34); + int Ytmp2 = Mem.ReadS32(curObj + 0x38); Xpos = (Xtmp >> 16) - _camX; Xpos2 = (Xtmp2 >> 16) - _camX; Ypos = (Ytmp >> 16) - _camY; Ypos2 = (Ytmp2 >> 16) - _camY; - Xvec = ((_api.MemLib.ReadS32(curObj + 0x24) + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((_api.MemLib.ReadS32(curObj + 0x28) + +_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xvec = ((Mem.ReadS32(curObj + 0x24) + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Mem.ReadS32(curObj + 0x28) + +Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); if (mode < 7) { double overlap = 0; - DrawEccoOct(Xmid, Ymid, 0x5C, _api.MemLib.ReadByte(curObj + 0x7C) == 0 ? Color.Blue : Color.Gray); + DrawEccoOct(Xmid, Ymid, 0x5C, Mem.ReadByte(curObj + 0x7C) == 0 ? Color.Blue : Color.Gray); DrawEccoOct(Xmid, Ymid, 0x5C, Color.Cyan, 0); - Xvec = (_api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)); - Yvec = (_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)); - subObj = _api.MemLib.ReadU24(curObj + 0x69); + Xvec = (Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)); + Yvec = (Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)); + subObj = Mem.ReadU24(curObj + 0x69); if (subObj != 0) { - Xpos = _api.MemLib.ReadS32(subObj + 0x2C); - Ypos = _api.MemLib.ReadS32(subObj + 0x30); - Xpos2 = _api.MemLib.ReadS32(subObj + 0x34); - Ypos2 = _api.MemLib.ReadS32(subObj + 0x38); + Xpos = Mem.ReadS32(subObj + 0x2C); + Ypos = Mem.ReadS32(subObj + 0x30); + Xpos2 = Mem.ReadS32(subObj + 0x34); + Ypos2 = Mem.ReadS32(subObj + 0x38); while ((Xtmp > Xpos) && (Xtmp2 < Xpos2) && (Ytmp > Ypos) && (Ytmp2 < Ypos2) && ((Xvec != 0) || (Yvec != 0))) { Xtmp += Xvec; Xtmp2 += Xvec; @@ -1304,19 +1321,19 @@ namespace BizHawk.Client.EmuHawk Ypos -= _camY; Ypos2 -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, 0); } - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, (overlap >= 6) ? 63 : 0); if (mode < 4) { - Xmid = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x50) - _camY; + Xmid = Mem.ReadS16(curObj + 0x4C) - _camX; + Ymid = Mem.ReadS16(curObj + 0x50) - _camY; if ((mode & 1) == 0) DrawEccoOct(Xmid, Ymid - 0xAE, 32, Color.Orange); if ((mode & 2) == 0) DrawEccoOct(Xmid, Ymid + 0xAE, 32, Color.Orange); } - TickerText($"{mode}:{_api.MemLib.ReadByte(curObj + 0x7F)}:{_api.MemLib.ReadByte(curObj + 0x6D)}:{_api.MemLib.ReadByte(curObj + 0x7C)}", Color.Red); + TickerText($"{mode}:{Mem.ReadByte(curObj + 0x7F)}:{Mem.ReadByte(curObj + 0x6D)}:{Mem.ReadByte(curObj + 0x7C)}", Color.Red); } else if (mode == 8) { @@ -1325,15 +1342,15 @@ namespace BizHawk.Client.EmuHawk } else if (type == 0xE1BA2) // Vortex Queen Boss { - var vulnCount = _api.MemLib.ReadByte(curObj + 0x7F); - var state = _api.MemLib.ReadByte(curObj + 0x7C); - var stateCounter = _api.MemLib.ReadU16(curObj + 0x6E); - var mode = _api.MemLib.ReadU16(curObj + 0x64); - var modeCounter = _api.MemLib.ReadU16(curObj + 0x66); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x40); - Xvec = Xmid + _api.MemLib.ReadS32(curObj + 0x54); - Yvec = Ymid + _api.MemLib.ReadS32(curObj + 0x58); + var vulnCount = Mem.ReadByte(curObj + 0x7F); + var state = Mem.ReadByte(curObj + 0x7C); + var stateCounter = Mem.ReadU16(curObj + 0x6E); + var mode = Mem.ReadU16(curObj + 0x64); + var modeCounter = Mem.ReadU16(curObj + 0x66); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x40); + Xvec = Xmid + Mem.ReadS32(curObj + 0x54); + Yvec = Ymid + Mem.ReadS32(curObj + 0x58); Xvec >>= 16; Yvec >>= 16; Xmid >>= 16; Ymid >>= 16; Xvec -= _camX; Yvec -= _camY; @@ -1350,35 +1367,35 @@ namespace BizHawk.Client.EmuHawk new Point(Xmid - hexOff.X, Ymid + 32), new Point(Xmid + hexOff.X, Ymid + 32) }; - _api.GUILib.DrawPolygon(roundedRect, Color.Orange, Color.FromArgb(63, Color.Orange)); + Gui.DrawPolygon(roundedRect, Color.Orange, Color.FromArgb(63, Color.Orange)); } DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - TickerText($"{state:X2}:{stateCounter}:{mode}:{modeCounter}:{_api.MemLib.ReadByte(curObj + 0x70) & 0xF}", Color.Red); - var subObj = _api.MemLib.ReadU24(curObj + 0x5); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{state:X2}:{stateCounter}:{mode}:{modeCounter}:{Mem.ReadByte(curObj + 0x70) & 0xF}", Color.Red); + var subObj = Mem.ReadU24(curObj + 0x5); var tongueMode = mode; - mode = _api.MemLib.ReadByte(subObj + 0x15); - modeCounter = _api.MemLib.ReadU16(subObj + 0x6E); - Xmid = _api.MemLib.ReadS32(subObj + 0x24); - Ymid = _api.MemLib.ReadS32(subObj + 0x40); - Xvec = (Xmid + _api.MemLib.ReadS32(subObj + 0x5C) >> 16) - _camX; - Yvec = (Ymid + _api.MemLib.ReadS32(subObj + 0x60) >> 16) - _camY; + mode = Mem.ReadByte(subObj + 0x15); + modeCounter = Mem.ReadU16(subObj + 0x6E); + Xmid = Mem.ReadS32(subObj + 0x24); + Ymid = Mem.ReadS32(subObj + 0x40); + Xvec = (Xmid + Mem.ReadS32(subObj + 0x5C) >> 16) - _camX; + Yvec = (Ymid + Mem.ReadS32(subObj + 0x60) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; Ymid -= 32; Yvec -= 32; - var levelHeight = _api.MemLib.ReadS16(0xFFA7AC) - _camY; + var levelHeight = Mem.ReadS16(0xFFA7AC) - _camY; switch (mode) { case 0: DrawBox(Xmid - 32, Ymid - ((state == 5) ? 0x60 : 0x70), Xmid + 32, Ymid - 16, Color.Red); break; case 2: - Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY; - _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + Ypos = Mem.ReadS16(subObj + 0x50) - _camY; + Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); break; case 3: - modeCounter = _api.MemLib.ReadByte(subObj + 0x7C); + modeCounter = Mem.ReadByte(subObj + 0x7C); break; case 5: Point[] throatShape = @@ -1390,7 +1407,7 @@ namespace BizHawk.Client.EmuHawk new Point(Xmid + 48, Ymid + 60), new Point(Xmid + 48, levelHeight) }; - _api.GUILib.DrawPolygon(throatShape, Color.Red, Color.FromArgb(63, Color.Red)); + Gui.DrawPolygon(throatShape, Color.Red, Color.FromArgb(63, Color.Red)); DrawEccoOct(Xmid, Ymid, 24, Color.Red); DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); break; @@ -1401,41 +1418,41 @@ namespace BizHawk.Client.EmuHawk } if (tongueMode == 7) { - uint subObj2 = _api.MemLib.ReadU24(0xFFCFCD); + uint subObj2 = Mem.ReadU24(0xFFCFCD); while (subObj2 != 0) { - if (_api.MemLib.ReadU16(subObj2 + 0x10) == 0xFF) + if (Mem.ReadU16(subObj2 + 0x10) == 0xFF) { - Xpos = _api.MemLib.ReadS16(subObj2 + 0x24) - _camX; - Ypos = _api.MemLib.ReadS16(subObj2 + 0x28) - _camY; - Xpos2 = ((_api.MemLib.ReadS32(subObj2 + 0x24) + _api.MemLib.ReadS32(subObj2 + 0x54)) >> 16) - _camX; - Ypos2 = ((_api.MemLib.ReadS32(subObj2 + 0x28) + _api.MemLib.ReadS32(subObj2 + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(subObj2 + 0x24) - _camX; + Ypos = Mem.ReadS16(subObj2 + 0x28) - _camY; + Xpos2 = ((Mem.ReadS32(subObj2 + 0x24) + Mem.ReadS32(subObj2 + 0x54)) >> 16) - _camX; + Ypos2 = ((Mem.ReadS32(subObj2 + 0x28) + Mem.ReadS32(subObj2 + 0x58)) >> 16) - _camY; DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); } - subObj2 = _api.MemLib.ReadU24(subObj2 + 1); + subObj2 = Mem.ReadU24(subObj2 + 1); } } - Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY; - _api.GUILib.DrawLine(Xmid - 48, Ypos - 94, Xmid + 48, Ypos - 94, Color.Orange); - _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + Ypos = Mem.ReadS16(subObj + 0x50) - _camY; + Gui.DrawLine(Xmid - 48, Ypos - 94, Xmid + 48, Ypos - 94, Color.Orange); + Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); break; default: break; } - if ((mode < 7) || ((mode == 7) && (_api.MemLib.ReadU24(0xFFCFC9) != 0))) + if ((mode < 7) || ((mode == 7) && (Mem.ReadU24(0xFFCFC9) != 0))) { - if (_api.MemLib.ReadByte(subObj + 0x70) == 0) + if (Mem.ReadByte(subObj + 0x70) == 0) { DrawEccoOct(Xmid, Ymid, 32, Color.Red); DrawBox(Xmid - 48, Ymid + 32, Xmid + 48, levelHeight, Color.Red); } - Ypos = _api.MemLib.ReadS16(subObj + 0x50) - _camY - 94; - _api.GUILib.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); + Ypos = Mem.ReadS16(subObj + 0x50) - _camY - 94; + Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); } - if (_api.MemLib.ReadS32(subObj + 0xC) == 0xE17B4) + if (Mem.ReadS32(subObj + 0xC) == 0xE17B4) { Point[] shapePoints = { @@ -1446,31 +1463,31 @@ namespace BizHawk.Client.EmuHawk new Point(Xmid + 48, Ymid + 60), new Point(Xmid + 48, levelHeight) }; - _api.GUILib.DrawPolygon(shapePoints, Color.Red, Color.FromArgb(63, Color.Red)); + Gui.DrawPolygon(shapePoints, Color.Red, Color.FromArgb(63, Color.Red)); DrawEccoOct(Xmid, Ymid, 24, Color.Red); DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); } - Ypos = (_api.MemLib.ReadS16(subObj + 0x50) - _camY) - 264; + Ypos = (Mem.ReadS16(subObj + 0x50) - _camY) - 264; DrawBoxMWH(160 + _left, Ypos, 320, 12, (32 < stateCounter) && (stateCounter < 160) ? Color.Brown : Color.Gray); if ((32 < stateCounter) && (stateCounter < 160)) { DrawBoxMWH(_left + 160, Ypos, 320, 12, Color.White, 0); } DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); TickerText($"{mode:X2}:{modeCounter}:{HP}:{vulnCount}", Color.Red); HP = 0; } else if (type == 0xA5BD2) // Telekinetic future dolphins { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; @@ -1479,66 +1496,66 @@ namespace BizHawk.Client.EmuHawk DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); DrawEccoOct(Xmid, Ymid, 4, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0x9F5B0) || (type == 0x9F4DC) || (type == 0x9F6A0)) // Falling rock, breaks barriers { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); if (type == 0x9F6A0) { - int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + int width = Mem.ReadS16(curObj + 0x44) << 1; DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); } - TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); } else if (type == 0xA3B18) { - Xpos = _api.MemLib.ReadS32(curObj + 0x24); - Ypos = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(curObj + 0x24); + Ypos = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Yellow); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(curObj + 0x44), Color.Yellow); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); } else if (type == 0xA4018) { - Xpos = _api.MemLib.ReadS32(curObj + 0x24); - Ypos = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS32(curObj + 0x24); + Ypos = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, _api.MemLib.ReadS16(curObj + 0x44), Color.Gray); + DrawEccoOct(Xpos, Ypos, Mem.ReadS16(curObj + 0x44), Color.Gray); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); } else if (type == 0xA091E) // Blue Whale { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; Xpos = Xmid; Ypos = Ymid; @@ -1548,39 +1565,39 @@ namespace BizHawk.Client.EmuHawk DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x30, Color.Red, 31); DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x20, Color.Red, 31); DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x10, Color.Red, 31); - if (_api.MemLib.ReadByte(curObj + 0x7F) == 0) + if (Mem.ReadByte(curObj + 0x7F) == 0) { - Xpos += (_api.MemLib.ReadS16(curObj + 0x6E) == 0) ? -278 : 162; - Ypos += 44 - _api.MemLib.ReadS16(curObj + 0x48); + Xpos += (Mem.ReadS16(curObj + 0x6E) == 0) ? -278 : 162; + Ypos += 44 - Mem.ReadS16(curObj + 0x48); DrawEccoOct(Xpos, Ypos, 32, Color.Blue); } DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xE66D8) //Vortex Larva { - uint subObj = _api.MemLib.ReadU24(curObj + 5); + uint subObj = Mem.ReadU24(curObj + 5); while (subObj != 0) { - Xpos = _api.MemLib.ReadS16(subObj + 0x1C); - Ypos = _api.MemLib.ReadS16(subObj + 0x20); - Xpos2 = _api.MemLib.ReadS16(subObj + 0x24); - Ypos2 = _api.MemLib.ReadS16(subObj + 0x28); + Xpos = Mem.ReadS16(subObj + 0x1C); + Ypos = Mem.ReadS16(subObj + 0x20); + Xpos2 = Mem.ReadS16(subObj + 0x24); + Ypos2 = Mem.ReadS16(subObj + 0x28); Xpos -= _camX; Ypos -= _camY; Xpos2 -= _camX; Ypos2 -= _camY; DrawEccoOct(Xpos, Ypos, 30, Color.White, 32); DrawEccoOct(Xpos, Ypos, 30, Color.Yellow, 0); DrawEccoOct(Xpos2, Ypos2, 30, Color.White, 32); DrawEccoOct(Xpos2, Ypos2, 30, Color.Yellow, 0); - subObj = _api.MemLib.ReadU24(subObj + 5); + subObj = Mem.ReadU24(subObj + 5); } - Xpos = _api.MemLib.ReadS32(curObj + 0x24); - Ypos = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x72) - _camX; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x76) - _camY; + Xpos = Mem.ReadS32(curObj + 0x24); + Ypos = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos2 = Mem.ReadS16(curObj + 0x72) - _camX; + Ypos2 = Mem.ReadS16(curObj + 0x76) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; DrawEccoOct(Xpos, Ypos, 0xB0, Color.Yellow); @@ -1588,112 +1605,112 @@ namespace BizHawk.Client.EmuHawk DrawEccoOct(Xpos, Ypos, 0x70, Color.Red); DrawEccoOct(Xpos, Ypos, 0x38, Color.White); DrawEccoOct(Xpos, Ypos, 0x38, Color.Red, 0); - DrawEccoOct(Xpos, Ypos, 48, Color.Blue, ((_api.MemLib.ReadByte(curObj + 0x7B) > 2) && (_api.MemLib.ReadByte(curObj + 0x14) != 0)) ? 63 : 0); + DrawEccoOct(Xpos, Ypos, 48, Color.Blue, ((Mem.ReadByte(curObj + 0x7B) > 2) && (Mem.ReadByte(curObj + 0x14) != 0)) ? 63 : 0); DrawEccoOct(Xpos2, Ypos2, 32, Color.Orange); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - TickerText($"{_api.MemLib.ReadByte(curObj + 0x14):X2}:{_api.MemLib.ReadByte(curObj + 0x7B):X2}:{_api.MemLib.ReadS16(curObj + 0x6E):D2}", Color.Red); - TickerText($"{ _api.MemLib.ReadByte(curObj + 0x7C):X2}:{_api.MemLib.ReadS16(curObj + 0x18):D3}", Color.Red); - TickerText($"{(_api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C))/65536.0:0.######}:{(_api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) / 65536.0:0.######}", Color.Red); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + TickerText($"{Mem.ReadByte(curObj + 0x14):X2}:{Mem.ReadByte(curObj + 0x7B):X2}:{Mem.ReadS16(curObj + 0x6E):D2}", Color.Red); + TickerText($"{ Mem.ReadByte(curObj + 0x7C):X2}:{Mem.ReadS16(curObj + 0x18):D3}", Color.Red); + TickerText($"{(Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C))/65536.0:0.######}:{(Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) / 65536.0:0.######}", Color.Red); } else if (type == 0x9CE3A) //Remnant Stars { - flags = _api.MemLib.ReadU16(curObj + 0x10); - uint subObj = _api.MemLib.ReadU24(curObj + 0x5); - uint anim = _api.MemLib.ReadU16(curObj + 0x6C); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); + flags = Mem.ReadU16(curObj + 0x10); + uint subObj = Mem.ReadU24(curObj + 0x5); + uint anim = Mem.ReadU16(curObj + 0x6C); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; if ((anim <= 7) && (subObj == 0xFFA9D4)) { DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); - PutText($"{((7 - anim) * 4) - ((_api.MemLib.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Blue, Color.Red); + PutText($"{((7 - anim) * 4) - ((Mem.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Blue, Color.Red); } } else if (type == 0xA997C) // Vortex Soldier { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = (Xmid + _api.MemLib.ReadS32(curObj + 0x54) >> 16) - _camX; - Yvec = (Ymid + _api.MemLib.ReadS32(curObj + 0x58) >> 16) - _camY; - Xvec += _api.MemLib.ReadS16(curObj + 0x64); - Yvec += _api.MemLib.ReadS16(curObj + 0x66); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = (Xmid + Mem.ReadS32(curObj + 0x54) >> 16) - _camX; + Yvec = (Ymid + Mem.ReadS32(curObj + 0x58) >> 16) - _camY; + Xvec += Mem.ReadS16(curObj + 0x64); + Yvec += Mem.ReadS16(curObj + 0x66); Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - if (_api.MemLib.ReadByte(curObj + 0x7A) == 0) + if (Mem.ReadByte(curObj + 0x7A) == 0) { DrawRectRhombusIntersection(new Point(Xmid, Ymid + 6), new Point(Xmid, Ymid), 50, 44, 64, Color.Red); } DrawRectRhombusIntersection(new Point(Xmid, Ymid - 25), new Point(Xmid, Ymid), 38, 47, 64, Color.Red); - DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue, 16); + DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue, 16); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xA6C4A) || (type == 0xC43D4)) // Barrier Glyphs { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - var subType = _api.MemLib.ReadByte(curObj + 0x13); - if ((_api.MemLib.ReadU8(curObj + 0x7A) == 0) && (_api.MemLib.ReadU8(0xFFA7B5) != 0) + var subType = Mem.ReadByte(curObj + 0x13); + if ((Mem.ReadU8(curObj + 0x7A) == 0) && (Mem.ReadU8(0xFFA7B5) != 0) && ((type != 0xA6C4A) || (subType == 0x14) || (subType == 0x97))) { DrawEccoOct(Xmid, Ymid, 70, Color.Red); } - DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue); - DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.PowderBlue, 0); + DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue); + DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.PowderBlue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xB4F46) || (type == 0xB4E1C) || (type == 0xB4C18) || (type == 0xB4ACC) || (type == 0xB4B72)) // Guiding Orca/Dolphin { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - int Xdst = _api.MemLib.ReadS16(curObj + 0x64); + int Xdst = Mem.ReadS16(curObj + 0x64); Xdst <<= 7; Xdst = Xdst + 0x40 - _camX; - int Ydst = _api.MemLib.ReadS16(curObj + 0x66); + int Ydst = Mem.ReadS16(curObj + 0x66); Ydst <<= 7; Ydst = Ydst + 0x40 - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - _api.GUILib.DrawLine(Xmid, Ymid, Xdst, Ydst, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xdst, Ydst, Color.Orange); DrawBoxMWH(Xdst, Ydst, 64, 64, Color.Orange); - TickerText($"{_api.MemLib.ReadS16(curObj + 0x24)}:{_api.MemLib.ReadS16(curObj + 0x28)}:{_api.MemLib.ReadByte(curObj + 0x7D)}:{_api.MemLib.ReadByte(curObj + 0x7A)}", Color.Lime); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x72) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x76) / 65536.0:0.######}", Color.Lime); + TickerText($"{Mem.ReadS16(curObj + 0x24)}:{Mem.ReadS16(curObj + 0x28)}:{Mem.ReadByte(curObj + 0x7D)}:{Mem.ReadByte(curObj + 0x7A)}", Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x72) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x76) / 65536.0:0.######}", Color.Lime); } else if (type == 0xB5938) // Lost Orca { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; //DrawBoxMWH(Xmid, Ymid, 64, 32, Color.Lime); - if (_api.MemLib.ReadU16(curObj + 0x6E) == 0) + if (Mem.ReadU16(curObj + 0x6E) == 0) { - if (_api.MemLib.ReadByte(curObj + 0x7D) == 0) + if (Mem.ReadByte(curObj + 0x7D) == 0) { DrawBox(Xmid + 8, Ymid - 32, Xmid + 64, Ymid + 32, Color.Red); } @@ -1702,87 +1719,87 @@ namespace BizHawk.Client.EmuHawk DrawBox(Xmid - 64, Ymid - 32, Xmid - 8, Ymid + 32, Color.Red); } } - _api.GUILib.DrawLine(Xpos - 80, Ymid, Xpos + 80, Ymid, Color.Green); + Gui.DrawLine(Xpos - 80, Ymid, Xpos + 80, Ymid, Color.Green); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xB552A) || (type == 0xB5C42) || (type == 0xB5AFE)) // Following Orca, Returning Orca, & Idling Orca { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xB624A) // Orca Mother { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; - int height = _api.MemLib.ReadS16(curObj + 0x48) + 32; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; + int height = Mem.ReadS16(curObj + 0x48) + 32; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 80, 32, Color.Red, 31); - DrawBoxMWH(Xmid, Ymid, _api.MemLib.ReadS16(curObj + 0x44), _api.MemLib.ReadS16(curObj + 0x48), Color.Blue); + DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - if (_api.MemLib.ReadS32(0xFFAB7E) != 0) + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + if (Mem.ReadS32(0xFFAB7E) != 0) { DrawEccoOct(Xmid, Ymid, 0x50, Color.Red, 31); } } else if (type == 0xC047E) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; var width = 2; var height = 2; - if (_api.MemLib.ReadByte(curObj + 0x15) == 0) + if (Mem.ReadByte(curObj + 0x15) == 0) { - width = _api.MemLib.ReadS16(curObj + 0x44); - height = _api.MemLib.ReadS16(curObj + 0x48); + width = Mem.ReadS16(curObj + 0x44); + height = Mem.ReadS16(curObj + 0x48); } DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); } else if (type == 0xC056E) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - var width = _api.MemLib.ReadS16(curObj + 0x44); - var height = _api.MemLib.ReadS16(curObj + 0x48); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + var width = Mem.ReadS16(curObj + 0x44); + var height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); } else if (type == 0xC4208) // Broken Glyph Base { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - var width = _api.MemLib.ReadS16(curObj + 0x44); - var height = _api.MemLib.ReadS16(curObj + 0x48); + var width = Mem.ReadS16(curObj + 0x44); + var height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.PowderBlue); - if (_api.MemLib.ReadByte(curObj + 0x15) == 0) + if (Mem.ReadByte(curObj + 0x15) == 0) { DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 80, 80, 120, Color.Orange); } DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xAC242) // Broken Glyph Top repairing { - uint subObj = _api.MemLib.ReadU24(curObj + 0x5); - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - Xpos = _api.MemLib.ReadS16(subObj + 0x24) - _camX; - Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; - var width = _api.MemLib.ReadS16(curObj + 0x44); - var height = _api.MemLib.ReadS16(curObj + 0x48); + uint subObj = Mem.ReadU24(curObj + 0x5); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + Xpos = Mem.ReadS16(subObj + 0x24) - _camX; + Ypos = Mem.ReadS16(subObj + 0x28) - _camY; + var width = Mem.ReadS16(curObj + 0x44); + var height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.Gray); Point[] rhombPoints = { @@ -1791,98 +1808,98 @@ namespace BizHawk.Client.EmuHawk new Point(Xpos + 3, Ypos), new Point(Xpos, Ypos + 3) }; - _api.GUILib.DrawPolygon(rhombPoints, Color.Orange, Color.FromArgb(63, Color.Orange)); + Gui.DrawPolygon(rhombPoints, Color.Orange, Color.FromArgb(63, Color.Orange)); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); } else if (type == 0xBE9C8) // Broken Glyph Top free { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xD9C0E) || (type == 0xDA9EA)) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBoxMWH(Xmid, Ymid, 0xA0, 0x70, Color.Red); } else if ((type == 0xBF204) || (type == 0xDA2C0)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xAF9CC) // Mirror Dolphin { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX + (_api.MemLib.ReadByte(curObj + 0x15) == 0 ? 27 : -27); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54) + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58) + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x1C) - _camX + (Mem.ReadByte(curObj + 0x15) == 0 ? 27 : -27); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - var width = _api.MemLib.ReadS16(curObj + 0x44); - var height = _api.MemLib.ReadS16(curObj + 0x48); + var width = Mem.ReadS16(curObj + 0x44); + var height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue, 31); - if (_api.MemLib.ReadByte(curObj + 0x13) != 0xAC) + if (Mem.ReadByte(curObj + 0x13) != 0xAC) { DrawBoxMWH(Xmid, Ymid, 96, 96, Color.Orange); } - _api.GUILib.DrawLine(Xpos, 0, Xpos, 448, Color.Red); + Gui.DrawLine(Xpos, 0, Xpos, 448, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xAF43E) // Vortex Lightning Trap { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - if (_api.MemLib.ReadByte(curObj + 0x15) != 0) + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + if (Mem.ReadByte(curObj + 0x15) != 0) { - if (_api.MemLib.ReadS16(0xFFAA12) != 0) + if (Mem.ReadS16(0xFFAA12) != 0) { Ymid -= 8; } DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Red); - PutText(_api.MemLib.ReadByte(curObj + 0x15).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); + PutText(Mem.ReadByte(curObj + 0x15).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); } else { DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Gray); - PutText(_api.MemLib.ReadByte(curObj + 0x7F).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); + PutText(Mem.ReadByte(curObj + 0x7F).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); } } else if (type == 0xA6E24) // Barrier Glyph Forcefield { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = _api.MemLib.ReadS32(0xFFAA1A) - Xmid; - Yvec = _api.MemLib.ReadS32(0xFFAA1E) - Ymid; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = Mem.ReadS32(0xFFAA1A) - Xmid; + Yvec = Mem.ReadS32(0xFFAA1E) - Ymid; var div = Math.Abs(Xvec) + Math.Abs(Yvec); Xvec /= div; Yvec /= div; Xvec += Xmid; Yvec += Ymid; @@ -1891,31 +1908,31 @@ namespace BizHawk.Client.EmuHawk Xmid -= _camX; Ymid -= _camY; Xvec -= _camX; Yvec -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xC4A44) || (type == 0xAA32C)) // Pulsar power-up and Vortex bullet-spawner { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue, 16); } else if (type == 0xC2F00) // Sky bubbles { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - var mode = _api.MemLib.ReadByte(curObj + 0x15); + var mode = Mem.ReadByte(curObj + 0x15); switch (mode) { case 0: @@ -1933,75 +1950,75 @@ namespace BizHawk.Client.EmuHawk break; } DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0x9FA7E) //Air refiller/drainer { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Lime)); } else if (type == 0xBFC14) //Pushable fish { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x54) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Orange); } else if ((type == 0xBE97C) //Slowing Kelp //Default Bounds nose-responsive || (type == 0xACDAE)) //Metasphere { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xACB42) // Turtle { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - var mode = _api.MemLib.ReadByte(curObj + 0x15); + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + var mode = Mem.ReadByte(curObj + 0x15); switch (mode) { case 0: case 1: case 2: case 3: - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x4C)) >> 16) - _camX; + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x4C)) >> 16) - _camX; break; case 4: case 5: case 6: case 7: - Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x4C)) >> 16) - _camX; + Xvec = ((Xmid - Mem.ReadS32(curObj + 0x4C)) >> 16) - _camX; break; default: Xvec = (Xmid >> 16) - _camX; @@ -2011,300 +2028,300 @@ namespace BizHawk.Client.EmuHawk Xmid >>= 16; Xmid -= _camX; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + int width = Mem.ReadS16(curObj + 0x44) << 1; DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); - TickerText($"{_api.MemLib.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xACA7E) // Retracting Turtle { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + (_api.MemLib.ReadS32(curObj + 0x4C) >> 1)) >> 16) - _camX; - Yvec = ((Ymid + (_api.MemLib.ReadS32(curObj + 0x50) >> 1)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + (Mem.ReadS32(curObj + 0x4C) >> 1)) >> 16) - _camX; + Yvec = ((Ymid + (Mem.ReadS32(curObj + 0x50) >> 1)) >> 16) - _camY; Xmid >>= 16; Xmid -= _camX; Ymid >>= 16; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - int width = _api.MemLib.ReadS16(curObj + 0x44) << 1; + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + int width = Mem.ReadS16(curObj + 0x44) << 1; DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); - TickerText($"{(_api.MemLib.ReadS32(curObj + 0x4C) >> 1) / 65536.0:0.######}:{(_api.MemLib.ReadS32(curObj + 0x50) >> 1) / 65536.0:0.######}", Color.Lime); + TickerText($"{(Mem.ReadS32(curObj + 0x4C) >> 1) / 65536.0:0.######}:{(Mem.ReadS32(curObj + 0x50) >> 1) / 65536.0:0.######}", Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xB5134) || (type == 0xA7E0C) //Default Bounds sonar-responsive || (type == 0xAF868) || (type == 0xAF960) || (type == 0xD8E5C) || (type == 0xAA5C6)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if ((type == 0xACCB4) || (type == 0xACD7E) //Default Baunds non-responsive || (type == 0xD8D96) || (type == 0xA955E) || (type == 0xA92E4) || (type == 0xC05DC) || (type == 0xC2684)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Gray); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0x9DE86) // Star Wreath { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - Xpos = _api.MemLib.ReadS32(curObj + 0x1C); - Ypos = _api.MemLib.ReadS32(curObj + 0x20); - Xpos2 = ((Xpos + _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Ypos2 = ((Ypos + _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xpos = Mem.ReadS32(curObj + 0x1C); + Ypos = Mem.ReadS32(curObj + 0x20); + Xpos2 = ((Xpos + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Ypos2 = ((Ypos + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - DrawBoxMWH(Xpos, Ypos, 1, 1, (_api.MemLib.ReadByte(curObj + 0x7F) == 0) ? Color.Blue : Color.Black, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - if (_api.MemLib.ReadByte(curObj + 0x12) % 7 == 0) + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + DrawBoxMWH(Xpos, Ypos, 1, 1, (Mem.ReadByte(curObj + 0x7F) == 0) ? Color.Blue : Color.Black, 0); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + if (Mem.ReadByte(curObj + 0x12) % 7 == 0) { - TickerText($"{_api.MemLib.ReadS32(curObj + 0x5C) / 65536.0:0.######}:{_api.MemLib.ReadS32(curObj + 0x60) / 65536.0:0.######}:{_api.MemLib.ReadByte(curObj + 0x7F)}", Color.Lime); + TickerText($"{Mem.ReadS32(curObj + 0x5C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x60) / 65536.0:0.######}:{Mem.ReadByte(curObj + 0x7F)}", Color.Lime); } } else if ((type == 0x9D774) || (type == 0x9DA26)) // Fish { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 0x14, 0x14, Color.Lime); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xAD87C) // Enemy dolphins in metamorph levels { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(_api.MemLib.ReadS16(curObj + 0x1C) - _camX, _api.MemLib.ReadS16(curObj + 0x20) - _camY, 1024, 1024, Color.Orange, 0); + DrawBoxMWH(Mem.ReadS16(curObj + 0x1C) - _camX, Mem.ReadS16(curObj + 0x20) - _camY, 1024, 1024, Color.Orange, 0); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xC6128) // Drone attacking dolphin { - Xmid = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x50) - _camY; + Xmid = Mem.ReadS16(curObj + 0x4C) - _camX; + Ymid = Mem.ReadS16(curObj + 0x50) - _camY; DrawEccoOct(Xmid, Ymid, 360, Color.Red, 0); } else if (type == 0xC605A) // Drone attacking dolphin sonar { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camY; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camY; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBox(Xmid, Ymid - 1, Xmid + 32, Ymid + 1, Color.Orange); } else if (type == 0xB1BE0) // Globe { - int mode = _api.MemLib.ReadS8(curObj + 0x15); + int mode = Mem.ReadS8(curObj + 0x15); if (mode == 1) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - _api.GUILib.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xB1A10) // Approaching globes { - Xmid = _api.MemLib.ReadS16(0xFFAA1A) - _camX; - Ymid = _api.MemLib.ReadS16(0xFFAA1E) - _camY; + Xmid = Mem.ReadS16(0xFFAA1A) - _camX; + Ymid = Mem.ReadS16(0xFFAA1E) - _camY; DrawEccoOct(Xmid - 56, Ymid, 8, Color.Orange); DrawEccoOct(Xmid + 56, Ymid, 8, Color.Orange); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xpos = _api.MemLib.ReadS32(curObj + 0x4C); - Ypos = _api.MemLib.ReadS32(curObj + 0x50); - Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos2 = ((Xpos + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Ypos2 = ((Ypos + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS32(curObj + 0x4C); + Ypos = Mem.ReadS32(curObj + 0x50); + Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos2 = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Ypos2 = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; Xpos >>= 16; Ypos >>= 16; Xpos -= _camX; Ypos -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); } else if (type == 0xB1920) // Orbiting globes { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xpos = _api.MemLib.ReadS16(curObj + 0x4C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x50) - _camY; - Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x60)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x4C) - _camX; + Ypos = Mem.ReadS16(curObj + 0x50) - _camY; + Xvec = ((Xmid - Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; + Yvec = ((Ymid - Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); } else if (type == 0xC28A0) // Control point in Four Islands/Dolphin that gives Rock-breaking song { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, _api.MemLib.ReadByte(curObj + 0x15) == 0 ? Color.Orange : Color.Blue); + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Mem.ReadByte(curObj + 0x15) == 0 ? Color.Orange : Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } // Crystal Springs merging glyphs else if (type == 0xC651E) // Bound glyph { - Xpos = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; + Ypos = Mem.ReadS16(curObj + 0x20) - _camY; DrawEccoRhomb(Xpos, Ypos, 4 << 4, Color.Orange); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xC67E4) // Freed glyph { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xC6970) // Pulled glyph { - uint subObj = _api.MemLib.ReadU24(curObj + 5); - Xvec = _api.MemLib.ReadS32(subObj + 0x54); - Yvec = _api.MemLib.ReadS32(subObj + 0x58); - for (i = 1; i < _api.MemLib.ReadByte(curObj + 0x7F); i++) + uint subObj = Mem.ReadU24(curObj + 5); + Xvec = Mem.ReadS32(subObj + 0x54); + Yvec = Mem.ReadS32(subObj + 0x58); + for (i = 1; i < Mem.ReadByte(curObj + 0x7F); i++) { Xvec ^= Yvec; Yvec ^= Xvec; Xvec ^= Yvec; Xvec = 0 - Xvec; } - Xpos = (Xvec + _api.MemLib.ReadS32(subObj + 0x1C) >> 16) - _camX; - Ypos = (Yvec + _api.MemLib.ReadS32(subObj + 0x20) >> 16) - _camY; + Xpos = (Xvec + Mem.ReadS32(subObj + 0x1C) >> 16) - _camX; + Ypos = (Yvec + Mem.ReadS32(subObj + 0x20) >> 16) - _camY; DrawEccoRhomb(Xpos, Ypos, 3, Color.Orange); - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); } else if (type == 0xC6BA8) // Delivery Point { - Xvec = _api.MemLib.ReadS32(curObj + 0x54); - Yvec = _api.MemLib.ReadS32(curObj + 0x58); - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xvec = Mem.ReadS32(curObj + 0x54); + Yvec = Mem.ReadS32(curObj + 0x58); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); for (i = 0; i < 4; i++) { - Xpos = (Xvec + _api.MemLib.ReadS32(curObj + 0x1C) >> 16) - _camX; - Ypos = (Yvec + _api.MemLib.ReadS32(curObj + 0x20) >> 16) - _camY; - _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + Xpos = (Xvec + Mem.ReadS32(curObj + 0x1C) >> 16) - _camX; + Ypos = (Yvec + Mem.ReadS32(curObj + 0x20) >> 16) - _camY; + Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); Xvec ^= Yvec; Yvec ^= Xvec; Xvec ^= Yvec; @@ -2313,46 +2330,46 @@ namespace BizHawk.Client.EmuHawk } else if (type == 0xC6A6C) // Delivered glyph { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xC6F82) // Full delivery point { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawEccoOct(Xmid, Ymid, 3, Color.Orange); } else if (type == 0xC6A9E) // Merging glyph { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid - _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xC7052) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS16(curObj + 0x24); - Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS16(curObj + 0x24); + Ymid = Mem.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; - uint dropSpeed = _api.MemLib.ReadU8(curObj + 0x16); + uint dropSpeed = Mem.ReadU8(curObj + 0x16); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xmid, Ymid + (int)(dropSpeed), Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xmid, Ymid + (int)(dropSpeed), Color.Orange); } else if ((type == 0xD8B7C) || (type == 0xD89EA) || (type == 0x9E3AA) || (type == 0x9E5A8) // GFX particles don't need displayed. || (type == 0x9B5D8) || (type == 0x9E2A6) || (type == 0xACD1E) || (type == 0xD9678) @@ -2380,14 +2397,14 @@ namespace BizHawk.Client.EmuHawk || (type == 0xC32C8) || (type == 0xAB5E6) || (type == 0xAC796) || (type == 0xAC9F2) || (type == 0xA538A)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; @@ -2397,7 +2414,7 @@ namespace BizHawk.Client.EmuHawk if (type != 0xA975E) { DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } if (HP > 2) { @@ -2406,33 +2423,33 @@ namespace BizHawk.Client.EmuHawk } else // Default bounds { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); PutText(type.ToString("X5"), Xmid, Ymid + 8, 1, 9, -1, -1, Color.Blue, Color.Red); } break; } case Modes.Ecco1: - type = _api.MemLib.ReadU32(curObj + 0x6); - Xpos = _api.MemLib.ReadS16(curObj + 0x17); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x1F); - Ypos = _api.MemLib.ReadS16(curObj + 0x1B); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x23); - Xmid = _api.MemLib.ReadS16(curObj + 0x0F); - Ymid = _api.MemLib.ReadS16(curObj + 0x13); + type = Mem.ReadU32(curObj + 0x6); + Xpos = Mem.ReadS16(curObj + 0x17); + Xpos2 = Mem.ReadS16(curObj + 0x1F); + Ypos = Mem.ReadS16(curObj + 0x1B); + Ypos2 = Mem.ReadS16(curObj + 0x23); + Xmid = Mem.ReadS16(curObj + 0x0F); + Ymid = Mem.ReadS16(curObj + 0x13); Xpos >>= 2; Xpos2 >>= 2; Ypos >>= 2; @@ -2446,13 +2463,13 @@ namespace BizHawk.Client.EmuHawk PutText(type.ToString("X8"), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); break; } - curObj = _api.MemLib.ReadU24(curObj+1); + curObj = Mem.ReadU24(curObj+1); } //events - curObj = _api.MemLib.ReadU24(0xFFCFB5); + curObj = Mem.ReadU24(0xFFCFB5); while (curObj != 0) { - type = _api.MemLib.ReadU32(curObj + 0xC); + type = Mem.ReadU32(curObj + 0xC); if ((type == 0) // Null object || (type == 0x9C1FA) || (type == 0x9C6D0) // Skytubes BG Image manager || (type == 0x9ED72) || (type == 0xA57F2) // And Miscellaneous GFX particles @@ -2460,22 +2477,22 @@ namespace BizHawk.Client.EmuHawk || (type == 0xB308A) || (type == 0xA1676) || (type == 0xB6822) || (type == 0xD12E2)) { } else if ((type == 0xA44EE) || (type == 0xD120C)) { - Xmid = _api.MemLib.ReadS16(curObj + 0x1C) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x20) - _camY; + Xmid = Mem.ReadS16(curObj + 0x1C) - _camX; + Ymid = Mem.ReadS16(curObj + 0x20) - _camY; DrawEccoOct(Xmid, Ymid, 0x20, Color.Red); } else if (type == 0x9F0D0) // Water Current { - int Xvec = _api.MemLib.ReadS32(curObj + 0x54); - int Yvec = _api.MemLib.ReadS32(curObj + 0x58); + int Xvec = Mem.ReadS32(curObj + 0x54); + int Yvec = Mem.ReadS32(curObj + 0x58); if ((Xvec != 0) || (Yvec != 0)) { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); Xvec += Xmid; Yvec += Ymid; Xmid >>= 16; Ymid >>= 16; Xvec >>= 16; Yvec >>= 16; @@ -2485,73 +2502,73 @@ namespace BizHawk.Client.EmuHawk Xvec -= _camX; Yvec -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Red)); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } } else if (type == 0xDEF94) { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawEccoOct(Xmid, Ymid, 0x18, Color.Cyan); } else if (type == 0xA6584) // Eagle { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawEccoOct(Xmid, Ymid, 0x10, Color.Red); } else if ((type == 0x9BA8A) // Autoscroller controller || (type == 0xE27D4) || (type == 0xE270E) || (type == 0xE26C2)) { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - var Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - var Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + var Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + var Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0x9B948) // Autoscroller waypoint { - Xmid = _api.MemLib.ReadS32(curObj + 0x24); - Ymid = _api.MemLib.ReadS32(curObj + 0x28); - var Xvec = ((Xmid + _api.MemLib.ReadS32(curObj + 0x54)) >> 16) - _camX; - var Yvec = ((Ymid + _api.MemLib.ReadS32(curObj + 0x58)) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj + 0x24); + Ymid = Mem.ReadS32(curObj + 0x28); + var Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; + var Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 8, 8, Color.Orange); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } else if (type == 0xA5448) // Bomb spawner { - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - PutText($"{_api.MemLib.ReadU16(curObj + 0x6E)}", Xmid, Ymid, 1, 1, -1, -1, Color.White, Color.Blue); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + PutText($"{Mem.ReadU16(curObj + 0x6E)}", Xmid, Ymid, 1, 1, -1, -1, Color.White, Color.Blue); } else if ((type == 0xA529C) || (type == 0xA5236) || (type == 0xA51E6)) // Explosion { - uint subObj = _api.MemLib.ReadU24(curObj + 5); + uint subObj = Mem.ReadU24(curObj + 5); if (subObj != 0) { - Xpos = _api.MemLib.ReadS16(subObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; - int Width = _api.MemLib.ReadS16(subObj + 0x24) - Xpos - _camX; + Xpos = Mem.ReadS16(subObj + 0x1C) - _camX; + Ypos = Mem.ReadS16(subObj + 0x28) - _camY; + int Width = Mem.ReadS16(subObj + 0x24) - Xpos - _camX; DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); } - subObj = _api.MemLib.ReadU24(curObj + 9); + subObj = Mem.ReadU24(curObj + 9); if (subObj != 0) { - Xpos = _api.MemLib.ReadS16(subObj + 0x1C) - _camX; - Ypos = _api.MemLib.ReadS16(subObj + 0x28) - _camY; - int Width = _api.MemLib.ReadS16(subObj + 0x24) - Xpos - _camX; + Xpos = Mem.ReadS16(subObj + 0x1C) - _camX; + Ypos = Mem.ReadS16(subObj + 0x28) - _camY; + int Width = Mem.ReadS16(subObj + 0x24) - Xpos - _camX; DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); } } else if (type == 0x9B5D8) { - var subtype = _api.MemLib.ReadByte(curObj + 0x13); + var subtype = Mem.ReadByte(curObj + 0x13); int width = 0; int height = 0; switch (subtype) @@ -2568,10 +2585,10 @@ namespace BizHawk.Client.EmuHawk case 59: case 87: case 181: - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - width = _api.MemLib.ReadS16(curObj + 0x44); - height = _api.MemLib.ReadS16(curObj + 0x48); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + width = Mem.ReadS16(curObj + 0x44); + height = Mem.ReadS16(curObj + 0x48); DrawEccoOct(Xmid, Ymid, (width + height) >> 1, Color.Lime); break; case 71: @@ -2579,10 +2596,10 @@ namespace BizHawk.Client.EmuHawk case 158: case 159: case 165: - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); break; case 82: @@ -2590,71 +2607,71 @@ namespace BizHawk.Client.EmuHawk case 84: case 85: case 86: - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - width = _api.MemLib.ReadS16(curObj + 0x44); - height = _api.MemLib.ReadS16(curObj + 0x48); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + width = Mem.ReadS16(curObj + 0x44); + height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.Red); break; case 210: - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; - width = _api.MemLib.ReadS16(curObj + 0x44); - height = _api.MemLib.ReadS16(curObj + 0x48); + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; + width = Mem.ReadS16(curObj + 0x44); + height = Mem.ReadS16(curObj + 0x48); DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue); break; case 107: - Xmid = (_api.MemLib.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; - Ymid = (_api.MemLib.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; - Xpos = (_api.MemLib.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; - Ypos = (_api.MemLib.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; + Xmid = (Mem.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; + Ymid = (Mem.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; + Xpos = (Mem.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; + Ypos = (Mem.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; DrawBoxMWH(Xmid, Ymid, 64, 64, Color.Orange, 0); DrawBoxMWH(Xpos, Ypos, 64, 64, Color.Orange, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); break; case 110: //Gravity conrol points case 179: - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63,_api.MemLib.ReadByte(curObj + 0x15) == 0 ? Color.Gray : Color.Red)); + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; + DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63,Mem.ReadByte(curObj + 0x15) == 0 ? Color.Gray : Color.Red)); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); - int dir = _api.MemLib.ReadS8(curObj + 0x71) & 7; + int dir = Mem.ReadS8(curObj + 0x71) & 7; int[] xtable = { 7, 4, -3, -10, -14, -11, -3, 4}; int[] ytable = { 11, 4, 7, 4, -3, -11, -14, -11}; - Xmid = _api.MemLib.ReadS16(curObj + 0x24) - _camX; - Ymid = _api.MemLib.ReadS16(curObj + 0x28) - _camY; + Xmid = Mem.ReadS16(curObj + 0x24) - _camX; + Ymid = Mem.ReadS16(curObj + 0x28) - _camY; DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawImage(".\\dll\\gravitometer_bg.png", Xmid - 15, Ymid - 15); - _api.GUILib.DrawImage(".\\dll\\gravitometer_fg.png", Xmid + xtable[dir], Ymid + ytable[dir]); + Gui.DrawImage(".\\dll\\gravitometer_bg.png", Xmid - 15, Ymid - 15); + Gui.DrawImage(".\\dll\\gravitometer_fg.png", Xmid + xtable[dir], Ymid + ytable[dir]); break; case 176: - Xmid = (_api.MemLib.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; - Ymid = (_api.MemLib.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; - Xpos = (_api.MemLib.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; - Ypos = (_api.MemLib.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; + Xmid = (Mem.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; + Ymid = (Mem.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; + Xpos = (Mem.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; + Ypos = (Mem.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; DrawEccoOct(Xmid, Ymid, 32, Color.Orange, 0); DrawEccoOct(Xpos, Ypos, 32, Color.Orange, 0); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); break; case 194: // Kill plane - Xpos = _api.MemLib.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34) - _camX; - Ypos = _api.MemLib.ReadS16(curObj + 0x30) - _camY; - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38) - _camY; + Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; + Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; + Ypos = Mem.ReadS16(curObj + 0x30) - _camY; + Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Black, 127); DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); break; default: - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2 = _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2 = _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS16(curObj + 0x24); - Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2 = Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2 = Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS16(curObj + 0x24); + Ymid = Mem.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; @@ -2666,58 +2683,58 @@ namespace BizHawk.Client.EmuHawk } else { - Xpos = _api.MemLib.ReadS16(curObj + 0x2C); - Xpos2= _api.MemLib.ReadS16(curObj + 0x34); - Ypos = _api.MemLib.ReadS16(curObj + 0x30); - Ypos2= _api.MemLib.ReadS16(curObj + 0x38); - Xmid = _api.MemLib.ReadS16(curObj + 0x24); - Ymid = _api.MemLib.ReadS16(curObj + 0x28); + Xpos = Mem.ReadS16(curObj + 0x2C); + Xpos2= Mem.ReadS16(curObj + 0x34); + Ypos = Mem.ReadS16(curObj + 0x30); + Ypos2= Mem.ReadS16(curObj + 0x38); + Xmid = Mem.ReadS16(curObj + 0x24); + Ymid = Mem.ReadS16(curObj + 0x28); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); - PutText($"{type:X5}:{_api.MemLib.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); + PutText($"{type:X5}:{Mem.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); } - curObj = _api.MemLib.ReadU24(curObj+1); + curObj = Mem.ReadU24(curObj+1); } //Ecco head - Xpos = _api.MemLib.ReadS16(0xFFA8F8); - Xpos2 = _api.MemLib.ReadS16(0xFFA900); - Ypos = _api.MemLib.ReadS16(0xFFA8FC); - Ypos2 = _api.MemLib.ReadS16(0xFFA904); - Xmid = _api.MemLib.ReadS16(0xFFA8F0); - Ymid = _api.MemLib.ReadS16(0xFFA8F4); + Xpos = Mem.ReadS16(0xFFA8F8); + Xpos2 = Mem.ReadS16(0xFFA900); + Ypos = Mem.ReadS16(0xFFA8FC); + Ypos2 = Mem.ReadS16(0xFFA904); + Xmid = Mem.ReadS16(0xFFA8F0); + Ymid = Mem.ReadS16(0xFFA8F4); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); //Ecco tail - Xpos = _api.MemLib.ReadS16(0xFFA978); - Xpos2 = _api.MemLib.ReadS16(0xFFA980); - Ypos = _api.MemLib.ReadS16(0xFFA97C); - Ypos2 = _api.MemLib.ReadS16(0xFFA984); - Xmid = _api.MemLib.ReadS16(0xFFA970); - Ymid = _api.MemLib.ReadS16(0xFFA974); + Xpos = Mem.ReadS16(0xFFA978); + Xpos2 = Mem.ReadS16(0xFFA980); + Ypos = Mem.ReadS16(0xFFA97C); + Ypos2 = Mem.ReadS16(0xFFA984); + Xmid = Mem.ReadS16(0xFFA970); + Ymid = Mem.ReadS16(0xFFA974); Xpos -= _camX; Xpos2 -= _camX; Ypos -= _camY; Ypos2 -= _camY; Xmid -= _camX; Ymid -= _camY; DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); //Ecco body - Xpos = _api.MemLib.ReadS32(0xFFAA22); - Ypos = _api.MemLib.ReadS32(0xFFAA26); - Xpos2 = _api.MemLib.ReadS32(0xFFAA2A); - Ypos2 = _api.MemLib.ReadS32(0xFFAA2E); - Xmid = _api.MemLib.ReadS16(0xFFAA1A); - Ymid = _api.MemLib.ReadS16(0xFFAA1E); - int Xvel = _api.MemLib.ReadS32(0xFFAA36); - if (_api.MemLib.ReadU32(0xFFA9D6) > 7) Xvel += _api.MemLib.ReadS32(0xFFA9D6); - if (_api.MemLib.ReadU32(0xFFAA3E) > 7) Xvel += _api.MemLib.ReadS32(0xFFAA3E); - int Yvel = _api.MemLib.ReadS32(0xFFAA3A); - if (_api.MemLib.ReadU32(0xFFA9DA) > 7) Yvel += _api.MemLib.ReadS32(0xFFA9DA); - if (_api.MemLib.ReadU32(0xFFAA42) > 7) Yvel += _api.MemLib.ReadS32(0xFFAA42); + Xpos = Mem.ReadS32(0xFFAA22); + Ypos = Mem.ReadS32(0xFFAA26); + Xpos2 = Mem.ReadS32(0xFFAA2A); + Ypos2 = Mem.ReadS32(0xFFAA2E); + Xmid = Mem.ReadS16(0xFFAA1A); + Ymid = Mem.ReadS16(0xFFAA1E); + int Xvel = Mem.ReadS32(0xFFAA36); + if (Mem.ReadU32(0xFFA9D6) > 7) Xvel += Mem.ReadS32(0xFFA9D6); + if (Mem.ReadU32(0xFFAA3E) > 7) Xvel += Mem.ReadS32(0xFFAA3E); + int Yvel = Mem.ReadS32(0xFFAA3A); + if (Mem.ReadU32(0xFFA9DA) > 7) Yvel += Mem.ReadS32(0xFFA9DA); + if (Mem.ReadU32(0xFFAA42) > 7) Yvel += Mem.ReadS32(0xFFAA42); int XV = ((Xpos + Xvel) >> 16) - _camX; int YV = ((Ypos + Yvel) >> 16) - _camY; int XV2 = ((Xpos2 + Xvel) >> 16) - _camX; @@ -2733,58 +2750,58 @@ namespace BizHawk.Client.EmuHawk int X4 = (Xmid + X2) >> 1; int Y3 = (Ymid + Y) >> 1; int Y4 = (Ymid + Y2) >> 1; - _api.GUILib.DrawLine(X, Y, Xmid, Ymid, Color.Green); - _api.GUILib.DrawLine(Xmid, Ymid, X2, Y2, Color.Green); + Gui.DrawLine(X, Y, Xmid, Ymid, Color.Green); + Gui.DrawLine(Xmid, Ymid, X2, Y2, Color.Green); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Red); DrawBoxMWH(X, Y, 1, 1, Color.Lime); DrawBoxMWH(X2, Y2, 1, 1, Color.Blue); DrawBoxMWH(X3, Y3, 1, 1, Color.Yellow); DrawBoxMWH(X4, Y4, 1, 1, Color.Yellow); - _api.GUILib.DrawLine(X, Y, XV, YV, Color.Orange); - _api.GUILib.DrawLine(X2, Y2, XV2, YV2, Color.Orange); + Gui.DrawLine(X, Y, XV, YV, Color.Orange); + Gui.DrawLine(X2, Y2, XV2, YV2, Color.Orange); // sonar - if (_api.MemLib.ReadU8(0xFFAB77) != 0) + if (Mem.ReadU8(0xFFAB77) != 0) { - Xmid = _api.MemLib.ReadS32(0xFFA9EC); - Ymid = _api.MemLib.ReadS32(0xFFA9F0); - int Xvec = ((_api.MemLib.ReadS32(0xFFAA04) + Xmid) >> 16) - _camX; - int Yvec = ((_api.MemLib.ReadS32(0xFFAA08) + Ymid) >> 16) - _camY; + Xmid = Mem.ReadS32(0xFFA9EC); + Ymid = Mem.ReadS32(0xFFA9F0); + int Xvec = ((Mem.ReadS32(0xFFAA04) + Xmid) >> 16) - _camX; + int Yvec = ((Mem.ReadS32(0xFFAA08) + Ymid) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; - Width2 = _api.MemLib.ReadS16(0xFFA9FC); - Height2 = _api.MemLib.ReadS16(0xFFAA00); - color = ((_api.MemLib.ReadU8(0xFFAA0C) != 0) ? Color.FromArgb(255, 0, 127) : Color.FromArgb(0, 0, 255)); + Width2 = Mem.ReadS16(0xFFA9FC); + Height2 = Mem.ReadS16(0xFFAA00); + color = ((Mem.ReadU8(0xFFAA0C) != 0) ? Color.FromArgb(255, 0, 127) : Color.FromArgb(0, 0, 255)); DrawBoxMWH(Xmid, Ymid, Width2, Height2, color); DrawBoxMWH(Xmid, Ymid, 1, 1, color, 0); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } //Pulsar - curObj = _api.MemLib.ReadU24(0xFFCFD1); - if ((curObj != 0) && ((_api.MemLib.ReadU32(curObj + 0xC) == 0xC9222) || (_api.MemLib.ReadU32(curObj + 0xC) == 0xC9456))) + curObj = Mem.ReadU24(0xFFCFD1); + if ((curObj != 0) && ((Mem.ReadU32(curObj + 0xC) == 0xC9222) || (Mem.ReadU32(curObj + 0xC) == 0xC9456))) { curObj += 0x26; for (int l = 0; l < 4; l++) { - if (_api.MemLib.ReadU16(curObj + 0x12) != 0) + if (Mem.ReadU16(curObj + 0x12) != 0) { - Xmid = _api.MemLib.ReadS32(curObj); - Ymid = _api.MemLib.ReadS32(curObj + 4); - int Xvec = (Xmid + _api.MemLib.ReadS32(curObj + 8) >> 16) - _camX; - int Yvec = (Ymid + _api.MemLib.ReadS32(curObj + 0xC) >> 16) - _camY; + Xmid = Mem.ReadS32(curObj); + Ymid = Mem.ReadS32(curObj + 4); + int Xvec = (Xmid + Mem.ReadS32(curObj + 8) >> 16) - _camX; + int Yvec = (Ymid + Mem.ReadS32(curObj + 0xC) >> 16) - _camY; Xmid >>= 16; Ymid >>= 16; Xmid -= _camX; Ymid -= _camY; DrawBoxMWH(Xmid, Ymid, 0x30, 0x30, Color.Red); DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); - _api.GUILib.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); + Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); } curObj += 0x14; } } //Water Level - int waterLevel = _api.MemLib.ReadS16(0xFFA7B2); - _api.GUILib.DrawLine(0, waterLevel - _camY, _left + 320 + _right, waterLevel - _camY, Color.Aqua); + int waterLevel = Mem.ReadS16(0xFFA7B2); + Gui.DrawLine(0, waterLevel - _camY, _left + 320 + _right, waterLevel - _camY, Color.Aqua); } @@ -2792,43 +2809,43 @@ namespace BizHawk.Client.EmuHawk { //Modif N - ECCO HACK - make caps lock (weirdly) autofire player 1's C key uint charge; - uint mode = _api.MemLib.ReadU8(0xFFA555); - int frameCount = _api.EmuLib.FrameCount(); - int lagCount = _api.EmuLib.LagCount(); - _api.JoypadLib.Set("Start", on, 1); + uint mode = Mem.ReadU8(0xFFA555); + int frameCount = Emu.FrameCount(); + int lagCount = Emu.LagCount(); + Joy.Set("Start", on, 1); switch (mode) { case 0x00: if (on) { - if (_api.MemLib.ReadU16(0xFFF342) == 0xFFFD) - _api.JoypadLib.Set("C", true, 1); + if (Mem.ReadU16(0xFFF342) == 0xFFFD) + Joy.Set("C", true, 1); else - _api.JoypadLib.Set("C", false, 1); + Joy.Set("C", false, 1); } break; case 0xE6: - if (_api.MemLib.ReadU16(0xFFD5E8) == 0x00000002) { + if (Mem.ReadU16(0xFFD5E8) == 0x00000002) { Dictionary buttons = new Dictionary(); buttons["B"] = buttons["C"] = true; - _api.JoypadLib.Set(buttons, 1); + Joy.Set(buttons, 1); } else { Dictionary buttons = new Dictionary(); buttons["B"] = buttons["C"] = false; - _api.JoypadLib.Set(buttons, 1); + Joy.Set(buttons, 1); } break; case 0xF6: - charge = _api.MemLib.ReadU8(0xFFB19B); + charge = Mem.ReadU8(0xFFB19B); if (on) { - if ((charge <= 1) && ((_api.MemLib.ReadU8(0xFFB1A6) == 0) || (_api.MemLib.ReadU8(0xFFB1A9) != 0))) - _api.JoypadLib.Set("B", true, 1); + if ((charge <= 1) && ((Mem.ReadU8(0xFFB1A6) == 0) || (Mem.ReadU8(0xFFB1A9) != 0))) + Joy.Set("B", true, 1); else if (charge > 1) - _api.JoypadLib.Set("B", false, 1); - _api.JoypadLib.Set("C", (_api.MemLib.ReadU16(0xFFA7C8) % 2) == 0, 1); + Joy.Set("B", false, 1); + Joy.Set("C", (Mem.ReadU16(0xFFA7C8) % 2) == 0, 1); } break; case 0x20: @@ -2836,19 +2853,19 @@ namespace BizHawk.Client.EmuHawk case 0xAC: if (on) { - if ((_api.MemLib.ReadU8(0xFFAB72) & 3) == 0) - _api.JoypadLib.Set("C", (_api.MemLib.ReadS8(0xFFAA6E) < 11), 1); + if ((Mem.ReadU8(0xFFAB72) & 3) == 0) + Joy.Set("C", (Mem.ReadS8(0xFFAA6E) < 11), 1); } break; default: break; } } - public override void Init(IPluginAPI api) + public override void Init(IApiContainer api) { base.Init(api); - _api.MemLib.SetBigEndian(); - string gameName = _api.GameInfoLib.GetRomName(); + Mem.SetBigEndian(); + string gameName = GI.GetRomName(); if ((gameName == "ECCO - The Tides of Time (J) [!]") || (gameName == "ECCO - The Tides of Time (U) [!]") || (gameName == "ECCO - The Tides of Time (E) [!]")) @@ -2858,7 +2875,7 @@ namespace BizHawk.Client.EmuHawk _camYAddr = 0xFFAD9E; _top = _bottom = 112; _left = _right = 160; - EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); + ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); } else if ((gameName == "ECCO The Dolphin (J) [!]") || (gameName == "ECCO The Dolphin (UE) [!]")) @@ -2869,7 +2886,7 @@ namespace BizHawk.Client.EmuHawk _camYAddr = 0xFFB834; _top = _bottom = 112; _left = _right = 160; - EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); + ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); } else { @@ -2879,48 +2896,47 @@ namespace BizHawk.Client.EmuHawk } private Color BackdropColor() { - uint color = _api.MemLib.ReadU16(0, "CRAM"); + uint color = Mem.ReadU16(0, "CRAM"); int r = (int)(( color & 0x7) * 0x22); int g = (int)(((color >> 3) & 0x7) * 0x22); int b = (int)(((color >> 6) & 0x7) * 0x22); return Color.FromArgb(r, g, b); - } public override void PreFrameCallback() { - _api.GUILib.ClearText(); + Gui.ClearText(); if (_mode != Modes.disabled) { - _camX = _api.MemLib.ReadS16(_camXAddr) - _left; - _camY = _api.MemLib.ReadS16(_camYAddr) - _top; - EccoAutofire(_api.JoypadLib.Get(1)["Start"]); + _camX = Mem.ReadS16(_camXAddr) - _left; + _camY = Mem.ReadS16(_camYAddr) - _top; + EccoAutofire(Joy.Get(1)["Start"]); if (_dumpMap == 0) { Color bg = BackdropColor(); - _api.GUILib.DrawRectangle(0, 0, _left + 320 + _right, _top, bg, bg); - _api.GUILib.DrawRectangle(0, 0, _left, _top + 224 + _bottom, bg, bg); - _api.GUILib.DrawRectangle(_left + 320, 0, _left + 320 + _right, _top + 224 + _bottom, bg, bg); - _api.GUILib.DrawRectangle(0, _top + 224, _left + 320 + _right, _top + 224 + _bottom, bg, bg); + Gui.DrawRectangle(0, 0, _left + 320 + _right, _top, bg, bg); + Gui.DrawRectangle(0, 0, _left, _top + 224 + _bottom, bg, bg); + Gui.DrawRectangle(_left + 320, 0, _left + 320 + _right, _top + 224 + _bottom, bg, bg); + Gui.DrawRectangle(0, _top + 224, _left + 320 + _right, _top + 224 + _bottom, bg, bg); } - uint mode = _api.MemLib.ReadByte(0xFFA555); + uint mode = Mem.ReadByte(0xFFA555); switch (mode) { case 0x20: case 0x28: case 0xAC: - //EmuHawkPluginLibrary.SetGameExtraPadding(160, 112, 160, 112); + //ClientApi.SetGameExtraPadding(160, 112, 160, 112); if (_dumpMap <= 1) EccoDrawBoxes(); // Uncomment the following block to enable mapdumping - if ((_api.MemLib.ReadU16(0xFFA7C8) > 1) && (_api.MemLib.ReadU16(0xFFA7C8) < 4)) + if ((Mem.ReadU16(0xFFA7C8) > 1) && (Mem.ReadU16(0xFFA7C8) < 4)) { _dumpMap = 1; _rowStateGuid = string.Empty; _top = _bottom = _left = _right = 0; - EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + ClientApi.SetGameExtraPadding(0, 0, 0, 0); } if (_dumpMap == 3) { - var levelID = _api.MemLib.ReadS8(0xFFA7D0); + var levelID = Mem.ReadS8(0xFFA7D0); int[] nameGroupLengths = { 7,1,11,6, @@ -2946,15 +2962,15 @@ namespace BizHawk.Client.EmuHawk if (i < 0) { i += nameGroupLengths[nameGroup]; - uint strOffset = _api.MemLib.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); + uint strOffset = Mem.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); Console.WriteLine($"{i}"); - strOffset = _api.MemLib.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); + strOffset = Mem.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); strOffset += 0x20; List strTmp = new List(); byte c; do { - c = (byte)_api.MemLib.ReadByte(strOffset++); + c = (byte)Mem.ReadByte(strOffset++); if (c != 0) strTmp.Add(c); } while (c != 0); @@ -2962,14 +2978,14 @@ namespace BizHawk.Client.EmuHawk TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); } - EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_top.png"); + ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_top.png"); _destX = _destY = 0; - EmuHawkPluginLibrary.SetGameExtraPadding(0, 0, 0, 0); + ClientApi.SetGameExtraPadding(0, 0, 0, 0); _dumpMap++; } if (_dumpMap == 6) { - var levelID = _api.MemLib.ReadS8(0xFFA7D0); + var levelID = Mem.ReadS8(0xFFA7D0); int[] nameGroupLengths = { 7,1,11,6, @@ -2995,15 +3011,15 @@ namespace BizHawk.Client.EmuHawk if (i < 0) { i += nameGroupLengths[nameGroup]; - uint strOffset = _api.MemLib.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); + uint strOffset = Mem.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); Console.WriteLine($"{i}"); - strOffset = _api.MemLib.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); + strOffset = Mem.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); strOffset += 0x20; List strTmp = new List(); byte c; do { - c = (byte)_api.MemLib.ReadByte(strOffset++); + c = (byte)Mem.ReadByte(strOffset++); if (c != 0) strTmp.Add(c); } while (c != 0); @@ -3011,11 +3027,11 @@ namespace BizHawk.Client.EmuHawk TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); } - EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_bottom.png"); + ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_bottom.png"); _destX = _destY = 0; _left = _right = 160; _top = _bottom = 112; - EmuHawkPluginLibrary.SetGameExtraPadding(_left, _top, _right, _bottom); + ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); _dumpMap = 0; } break; @@ -3025,52 +3041,52 @@ namespace BizHawk.Client.EmuHawk default: break; } - _prevF = _api.MemLib.ReadU32(0xFFA524); + _prevF = Mem.ReadU32(0xFFA524); } } public override void PostFrameCallback() { - uint frame = _api.MemLib.ReadU32(0xFFA524); - if ((frame <= _prevF) && !_api.EmuLib.IsLagged()) + uint frame = Mem.ReadU32(0xFFA524); + if ((frame <= _prevF) && !Emu.IsLagged()) { - _api.EmuLib.SetIsLagged(true); - _api.EmuLib.SetLagCount(_api.EmuLib.LagCount() + 1); + Emu.SetIsLagged(true); + Emu.SetLagCount(Emu.LagCount() + 1); } - uint mode = _api.MemLib.ReadByte(0xFFA555); + uint mode = Mem.ReadByte(0xFFA555); _tickerY = 81; - string valueTicker = $"{_api.MemLib.ReadU32(0xFFA520)}:{_api.MemLib.ReadU32(0xFFA524)}:{_api.MemLib.ReadU16(0xFFA7C8)}:{mode:X2}"; + string valueTicker = $"{Mem.ReadU32(0xFFA520)}:{Mem.ReadU32(0xFFA524)}:{Mem.ReadU16(0xFFA7C8)}:{mode:X2}"; TickerText(valueTicker); switch (mode) { case 0x20: case 0x28: case 0xAC: - valueTicker = $"{_api.MemLib.ReadS16(0xFFAD9C)}:{_api.MemLib.ReadS16(0xFFAD9E)}"; + valueTicker = $"{Mem.ReadS16(0xFFAD9C)}:{Mem.ReadS16(0xFFAD9E)}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFAA1A) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA1E) / 65536.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFAA1A) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA1E) / 65536.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFAA32) / 65536.0:0.######}:{_api.MemLib.ReadU8(0xFFAA6D)}:{_api.MemLib.ReadU8(0xFFAA6E)}"; + valueTicker = $"{Mem.ReadS32(0xFFAA32) / 65536.0:0.######}:{Mem.ReadU8(0xFFAA6D)}:{Mem.ReadU8(0xFFAA6E)}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFAA36) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA3A) / 65536.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFAA36) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA3A) / 65536.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFA9D6) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFA9DA) / 65536.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFA9D6) / 65536.0:0.######}:{Mem.ReadS32(0xFFA9DA) / 65536.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFAA3E) / 65536.0:0.######}:{_api.MemLib.ReadS32(0xFFAA42) / 65536.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFAA3E) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA42) / 65536.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{(_api.MemLib.ReadS32(0xFFAA36) + _api.MemLib.ReadS32(0xFFA9D6) + _api.MemLib.ReadS32(0xFFAA3E)) / 65536.0:0.######}:" + - $"{(_api.MemLib.ReadS32(0xFFAA3A) + _api.MemLib.ReadS32(0xFFA9DA) + _api.MemLib.ReadS32(0xFFAA42)) / 65536.0:0.######}"; + valueTicker = $"{(Mem.ReadS32(0xFFAA36) + Mem.ReadS32(0xFFA9D6) + Mem.ReadS32(0xFFAA3E)) / 65536.0:0.######}:" + + $"{(Mem.ReadS32(0xFFAA3A) + Mem.ReadS32(0xFFA9DA) + Mem.ReadS32(0xFFAA42)) / 65536.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadU8(0xFFAB72)}:{_api.MemLib.ReadU8(0xFFAB70)}:{(short)_api.MemLib.ReadS16(0xFFAA52):X4}:{(short)_api.MemLib.ReadS16(0xFFAA5A):X4}"; + valueTicker = $"{Mem.ReadU8(0xFFAB72)}:{Mem.ReadU8(0xFFAB70)}:{(short)Mem.ReadS16(0xFFAA52):X4}:{(short)Mem.ReadS16(0xFFAA5A):X4}"; TickerText(valueTicker); - switch (_api.MemLib.ReadU8(0xFFA7D0)) + switch (Mem.ReadU8(0xFFA7D0)) { case 1: case 2: case 3: case 30: case 46: - var globeFlags = _api.MemLib.ReadU32(0xFFD434) >> 1; - var globeFlags2 = _api.MemLib.ReadU32(0xFFD438) >> 1; + var globeFlags = Mem.ReadU32(0xFFD434) >> 1; + var globeFlags2 = Mem.ReadU32(0xFFD438) >> 1; int i, j = i = 0; while (globeFlags > 0) { @@ -3089,33 +3105,33 @@ namespace BizHawk.Client.EmuHawk } if (_dumpMap != 0) { - _api.MemLib.WriteS16(0xFFAA16, 7); - _api.MemLib.WriteS16(0xFFAA18, 56); - int PlayerX = _api.MemLib.ReadS16(0xFFAA1A) - _camX; - int PlayerY = _api.MemLib.ReadS16(0xFFAA1E) - _camY; + Mem.WriteS16(0xFFAA16, 7); + Mem.WriteS16(0xFFAA18, 56); + int PlayerX = Mem.ReadS16(0xFFAA1A) - _camX; + int PlayerY = Mem.ReadS16(0xFFAA1E) - _camY; if ((PlayerX < -64) || (PlayerX > 384) || (PlayerY < -64) || (PlayerY > 288)) { - _api.MemLib.WriteByte(0xFFAA70, 0xC); - _api.MemLib.WriteS16(0xFFA7CA, 1); + Mem.WriteByte(0xFFAA70, 0xC); + Mem.WriteS16(0xFFA7CA, 1); } else { - _api.MemLib.WriteByte(0xFFAA70, 0x0); - _api.MemLib.WriteS16(0xFFA7CA, 0); + Mem.WriteByte(0xFFAA70, 0x0); + Mem.WriteS16(0xFFA7CA, 0); } } if (_dumpMap == 1) { - int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); - int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); - var levelID = _api.MemLib.ReadByte(0xFFA7D0); - var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + int levelWidth = Mem.ReadS16(0xFFA7A8); + int levelHeight = Mem.ReadS16(0xFFA7AC); + var levelID = Mem.ReadByte(0xFFA7D0); + var s = Emu.GetSettings() as GPGX.GPGXSettings; s.DrawBGA = false; s.DrawBGB = false; s.DrawBGW = false; s.DrawObj = false; s.Backdrop = true; - _api.EmuLib.PutSettings(s); + Emu.PutSettings(s); if ((_camX == _destX) && (_camY == _destY)) { if ((_prevX != _camX) || (_prevY != _camY)) @@ -3124,9 +3140,9 @@ namespace BizHawk.Client.EmuHawk { if (_rowStateGuid != string.Empty) { - _api.MemStateLib.DeleteState(_rowStateGuid); + MemSS.DeleteState(_rowStateGuid); } - _rowStateGuid = _api.MemStateLib.SaveCoreStateToMemory(); + _rowStateGuid = MemSS.SaveCoreStateToMemory(); } _snapPast = 1; } @@ -3136,14 +3152,14 @@ namespace BizHawk.Client.EmuHawk } if (_snapPast == 0) { - EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_top.png"); + ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_top.png"); if (_destX >= levelWidth - 320) { if (_destY < levelHeight - 224) { if (_rowStateGuid != string.Empty) { - _api.MemStateLib.LoadCoreStateFromMemory(_rowStateGuid); + MemSS.LoadCoreStateFromMemory(_rowStateGuid); } _destX = 0; _destY = Math.Min(_destY + 111, levelHeight - 224); @@ -3153,70 +3169,70 @@ namespace BizHawk.Client.EmuHawk _destX = Math.Min(_destX + 159, levelWidth - 320); if ((_prevX == _destX) && (_prevY == _destY)) { - EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); _dumpMap++; } } } - _api.MemLib.WriteS16(0xFFAD8C, _destX); - _api.MemLib.WriteS16(0xFFAD90, _destY); + Mem.WriteS16(0xFFAD8C, _destX); + Mem.WriteS16(0xFFAD90, _destY); } else if (_dumpMap == 2) { if (_rowStateGuid != String.Empty) - _api.MemStateLib.DeleteState(_rowStateGuid); + MemSS.DeleteState(_rowStateGuid); _rowStateGuid = String.Empty; - int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); - int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); - EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); - var levelID = _api.MemLib.ReadS8(0xFFA7D0); - var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + int levelWidth = Mem.ReadS16(0xFFA7A8); + int levelHeight = Mem.ReadS16(0xFFA7AC); + ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + var levelID = Mem.ReadS8(0xFFA7D0); + var s = Emu.GetSettings() as GPGX.GPGXSettings; s.DrawBGA = false; s.DrawBGB = false; s.DrawBGW = false; s.DrawObj = false; s.Backdrop = true; - _api.EmuLib.PutSettings(s); + Emu.PutSettings(s); - var a = _api.GUILib.GetAttributes(); + var a = Gui.GetAttributes(); a.SetColorKey(Color.FromArgb(0, 0x11, 0x22, 0x33), Color.FromArgb(0, 0x11, 0x22, 0x33)); - _api.GUILib.SetAttributes(a); - _api.GUILib.ToggleCompositingMode(); + Gui.SetAttributes(a); + Gui.ToggleCompositingMode(); - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_top.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_top.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) { var dx = (x == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_top.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_top.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); } for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) { var dy = (y == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_top.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_top.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) { var dx = (x == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_top.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_top.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); } } - _api.GUILib.ToggleCompositingMode(); - _api.GUILib.SetAttributes(new System.Drawing.Imaging.ImageAttributes()); - _api.GUILib.DrawFinish(); + Gui.ToggleCompositingMode(); + Gui.SetAttributes(new System.Drawing.Imaging.ImageAttributes()); + Gui.DrawFinish(); _dumpMap++; } else if (_dumpMap == 4) { - int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); - int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); - var levelID = _api.MemLib.ReadByte(0xFFA7D0); - var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + int levelWidth = Mem.ReadS16(0xFFA7A8); + int levelHeight = Mem.ReadS16(0xFFA7AC); + var levelID = Mem.ReadByte(0xFFA7D0); + var s = Emu.GetSettings() as GPGX.GPGXSettings; s.DrawBGA = (levelID != 29); s.DrawBGB = (levelID == 7); s.DrawBGW = true; s.DrawObj = true; s.Backdrop = false; - _api.EmuLib.PutSettings(s); + Emu.PutSettings(s); if ((_camX == _destX) && (_camY == _destY)) { if ((_prevX != _camX) || (_prevY != _camY)) @@ -3225,9 +3241,9 @@ namespace BizHawk.Client.EmuHawk { if (_rowStateGuid != string.Empty) { - _api.MemStateLib.DeleteState(_rowStateGuid); + MemSS.DeleteState(_rowStateGuid); } - _rowStateGuid = _api.MemStateLib.SaveCoreStateToMemory(); + _rowStateGuid = MemSS.SaveCoreStateToMemory(); } _snapPast = 1; } @@ -3237,14 +3253,14 @@ namespace BizHawk.Client.EmuHawk } if (_snapPast == 0) { - EmuHawkPluginLibrary.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_bottom.png"); + ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_bottom.png"); if (_destX >= levelWidth - 320) { if (_destY < levelHeight - 224) { if (_rowStateGuid != string.Empty) { - _api.MemStateLib.LoadCoreStateFromMemory(_rowStateGuid); + MemSS.LoadCoreStateFromMemory(_rowStateGuid); } _destX = 0; _destY = Math.Min(_destY + 111, levelHeight - 224); @@ -3254,80 +3270,80 @@ namespace BizHawk.Client.EmuHawk _destX = Math.Min(_destX + 159, levelWidth - 320); if ((_prevX == _destX) && (_prevY == _destY)) { - EmuHawkPluginLibrary.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); + ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); _dumpMap++; } } } - _api.MemLib.WriteS16(0xFFAD8C, _destX); - _api.MemLib.WriteS16(0xFFAD90, _destY); + Mem.WriteS16(0xFFAD8C, _destX); + Mem.WriteS16(0xFFAD90, _destY); } else if (_dumpMap == 5) { if (_rowStateGuid != String.Empty) - _api.MemStateLib.DeleteState(_rowStateGuid); + MemSS.DeleteState(_rowStateGuid); _rowStateGuid = String.Empty; - int levelWidth = _api.MemLib.ReadS16(0xFFA7A8); - int levelHeight = _api.MemLib.ReadS16(0xFFA7AC); - var levelID = _api.MemLib.ReadS8(0xFFA7D0); - var s = _api.EmuLib.GetSettings() as GPGX.GPGXSettings; + int levelWidth = Mem.ReadS16(0xFFA7A8); + int levelHeight = Mem.ReadS16(0xFFA7AC); + var levelID = Mem.ReadS8(0xFFA7D0); + var s = Emu.GetSettings() as GPGX.GPGXSettings; s.DrawBGA = (levelID != 29); s.DrawBGB = (levelID == 7); s.DrawBGW = true; s.DrawObj = true; s.Backdrop = false; - _api.EmuLib.PutSettings(s); - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_bottom.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); + Emu.PutSettings(s); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_bottom.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) { var dx = (x == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_bottom.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_bottom.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); } for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) { var dy = (y == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_bottom.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_bottom.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) { var dx = (x == 0) ? 0 : 2; - _api.GUILib.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_bottom.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); + Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_bottom.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); } } - _api.GUILib.DrawFinish(); + Gui.DrawFinish(); _dumpMap++; } _prevX = _camX; _prevY = _camY; break; case 0xF6: - valueTicker = $"{_api.MemLib.ReadS32(0xFFD5E0) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD5E8) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD5E4) / 2048.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFD5E0) / 4096.0:0.######}:{Mem.ReadS32(0xFFD5E8) / 4096.0:0.######}:{Mem.ReadS32(0xFFD5E4) / 2048.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFB13A) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB142) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB13E) / 2048.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFB13A) / 4096.0:0.######}:{Mem.ReadS32(0xFFB142) / 4096.0:0.######}:{Mem.ReadS32(0xFFB13E) / 2048.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadS32(0xFFB162) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB16A) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFB166) / 2048.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFB162) / 4096.0:0.######}:{Mem.ReadS32(0xFFB16A) / 4096.0:0.######}:{Mem.ReadS32(0xFFB166) / 2048.0:0.######}"; TickerText(valueTicker); - valueTicker = $"{_api.MemLib.ReadU8(0xFFB19B)}:{_api.MemLib.ReadU8(0xFFB1A6)}:{_api.MemLib.ReadU8(0xFFB1A9)}"; + valueTicker = $"{Mem.ReadU8(0xFFB19B)}:{Mem.ReadU8(0xFFB1A6)}:{Mem.ReadU8(0xFFB1A9)}"; TickerText(valueTicker); - int SpawnZ = _api.MemLib.ReadS32(0xFFD5F0) + 0x180000; + int SpawnZ = Mem.ReadS32(0xFFD5F0) + 0x180000; int nextRingZ = SpawnZ; while (((nextRingZ >> 17) & 0xF) != 0) { nextRingZ += 0x20000; } - valueTicker = $"{_api.MemLib.ReadS32(0xFFD856) / 4096.0:0.######}:{_api.MemLib.ReadS32(0xFFD85A) / 4096.0:0.######}:{(nextRingZ - 0x160000) / 2048.0:0.######}:{nextRingZ / 2048.0:0.######}"; + valueTicker = $"{Mem.ReadS32(0xFFD856) / 4096.0:0.######}:{Mem.ReadS32(0xFFD85A) / 4096.0:0.######}:{(nextRingZ - 0x160000) / 2048.0:0.######}:{nextRingZ / 2048.0:0.######}"; TickerText(valueTicker); - var levelId = -1 - _api.MemLib.ReadS16(0xFFA79E); + var levelId = -1 - Mem.ReadS16(0xFFA79E); bool spawn = false; bool firstRand = true; int SpawnX, SpawnY, z; - int CamX = (_api.MemLib.ReadS32(0xFFD5E0) >> 0xC) - _left; - int CamY = (_api.MemLib.ReadS32(0xFFD5E8) >> 0xC) + _top; - int CamZ = (_api.MemLib.ReadS32(0xFFD5E4) >> 0xC) + _top; + int CamX = (Mem.ReadS32(0xFFD5E0) >> 0xC) - _left; + int CamY = (Mem.ReadS32(0xFFD5E8) >> 0xC) + _top; + int CamZ = (Mem.ReadS32(0xFFD5E4) >> 0xC) + _top; while (!spawn) { var temp = (SpawnZ >> 17) & 0xFF; - var controlList = _api.MemLib.ReadS32(0x7B54 + (levelId << 2)); - temp = _api.MemLib.ReadS16(controlList + (temp << 1)); + var controlList = Mem.ReadS32(0x7B54 + (levelId << 2)); + temp = Mem.ReadS16(controlList + (temp << 1)); var v = temp & 0xFF; var num = (temp >> 8) + v; temp = v; @@ -3343,7 +3359,7 @@ namespace BizHawk.Client.EmuHawk break; case 2: // Jellyfish - SpawnX = _api.MemLib.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); + SpawnX = Mem.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); firstRand = false; SpawnY = -0xC0000 + (EccoRand() << 3); z = SpawnZ + 0x20000;// ? @@ -3357,7 +3373,7 @@ namespace BizHawk.Client.EmuHawk break; case 3: // Eagle - SpawnX = _api.MemLib.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); + SpawnX = Mem.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); firstRand = false; SpawnY = 0x50000; z = SpawnZ - 0x40000 + 0x20000;// ? @@ -3374,8 +3390,8 @@ namespace BizHawk.Client.EmuHawk bool left = (EccoRand(firstRand) > 0x8000); firstRand = false; var xdiff = 0xC0000 + (EccoRand() << 3); - SpawnX = _api.MemLib.ReadS32(0xFFB13A) + (left ? -xdiff : xdiff); - SpawnY = Math.Min(_api.MemLib.ReadS32(0xFFB142), -0x10000) - (EccoRand() + 0x10000); + SpawnX = Mem.ReadS32(0xFFB13A) + (left ? -xdiff : xdiff); + SpawnY = Math.Min(Mem.ReadS32(0xFFB142), -0x10000) - (EccoRand() + 0x10000); z = SpawnZ + 0x20000; valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; TickerText(valueTicker); @@ -3406,7 +3422,7 @@ namespace BizHawk.Client.EmuHawk break; case 14: // Shell - SpawnX = _api.MemLib.ReadS32(0xFFB13A) - 0x20000 + (EccoRand(firstRand) << 2); + SpawnX = Mem.ReadS32(0xFFB13A) - 0x20000 + (EccoRand(firstRand) << 2); firstRand = false; SpawnY = -0x80000; z = SpawnZ + 0x20000; @@ -3425,16 +3441,16 @@ namespace BizHawk.Client.EmuHawk } break; } - _api.JoypadLib.Set("C", null, 1); - _api.JoypadLib.Set("Start", null, 1); - var color = _turnSignalColors[_api.MemLib.ReadS8(0xFFA7C9) & 7]; - _api.GUILib.DrawRectangle(_left - 48, _top - 112, 15, 15, color, color); + Joy.Set("C", null, 1); + Joy.Set("Start", null, 1); + var color = _turnSignalColors[Mem.ReadS8(0xFFA7C9) & 7]; + Gui.DrawRectangle(_left - 48, _top - 112, 15, 15, color, color); } public override void LoadStateCallback(string name) { - _api.GUILib.DrawNew("emu"); + Gui.DrawNew("emu"); PreFrameCallback(); - _api.GUILib.DrawFinish(); + Gui.DrawFinish(); } } } diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs b/BizHawk.Client.EmuHawk/Api/Libraries/CommApi.cs similarity index 95% rename from BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs rename to BizHawk.Client.EmuHawk/Api/Libraries/CommApi.cs index 43012c1817..152658c639 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Communications.cs +++ b/BizHawk.Client.EmuHawk/Api/Libraries/CommApi.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using BizHawk.Emulation.Common; -using BizHawk.Client.Common; +using BizHawk.Client.ApiHawk; using System.Text; using System.Collections.Generic; using System.Net.Http; @@ -11,7 +11,7 @@ using System.Windows.Forms; namespace BizHawk.Client.EmuHawk { - public sealed class CommunicationPluginLibrary : PluginLibraryBase + public sealed class CommApi : IComm { [RequiredService] private IEmulator Emulator { get; set; } @@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk [RequiredService] private IVideoProvider VideoProvider { get; set; } - public CommunicationPluginLibrary() : base() + public CommApi() : base() { } public string SocketServerScreenShot() diff --git a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs b/BizHawk.Client.EmuHawk/Api/Libraries/GUIApi.cs similarity index 65% rename from BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs rename to BizHawk.Client.EmuHawk/Api/Libraries/GUIApi.cs index 2647c19a89..5270a6eece 100644 --- a/BizHawk.Client.Common/plugins/PluginLibrary.GUIDraw.cs +++ b/BizHawk.Client.EmuHawk/Api/Libraries/GUIApi.cs @@ -5,44 +5,47 @@ using System.Drawing.Imaging; using System.Windows.Forms; using System.IO; +using BizHawk.Client.ApiHawk; using BizHawk.Emulation.Common; -namespace BizHawk.Client.Common +namespace BizHawk.Client.EmuHawk { - public abstract class GUIDrawPluginBase : PluginLibraryBase + public sealed class GuiApi : IGui { [RequiredService] - protected IEmulator Emulator { get; set; } - - public GUIDrawPluginBase() : base() - { } - - public bool HasGUISurface = false; - - protected Color _defaultForeground = Color.White; - protected Color? _defaultBackground; - protected Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); - protected int _defaultPixelFont = 1; // gens - protected Padding _padding = new Padding(0); - protected ImageAttributes _attributes = new ImageAttributes(); + private IEmulator Emulator { get; set; } + private Color _defaultForeground = Color.White; + private Color? _defaultBackground; + private Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); + private int _defaultPixelFont = 1; // gens + private Padding _padding = new Padding(0); + private ImageAttributes _attributes = new ImageAttributes(); private System.Drawing.Drawing2D.CompositingMode _compositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; - public virtual void ToggleCompositingMode() + + public GuiApi() + { } + + private DisplaySurface _GUISurface = null; + + public bool HasGUISurface => _GUISurface != null; + + #region Gui API + public void ToggleCompositingMode() { _compositingMode = 1 - _compositingMode; } - public virtual ImageAttributes GetAttributes() + public ImageAttributes GetAttributes() { return _attributes; } - public virtual void SetAttributes(ImageAttributes a) + public void SetAttributes(ImageAttributes a) { _attributes = a; } - #region Gui API - public virtual void Dispose() + public void Dispose() { foreach (var brush in _solidBrushes.Values) { @@ -55,16 +58,35 @@ namespace BizHawk.Client.Common } } - public abstract void DrawNew(string name, bool? clear = true); - public abstract void DrawFinish(); + public void DrawNew(string name, bool? clear = true) + { + try + { + DrawFinish(); + _GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true); + } + catch (InvalidOperationException ex) + { + Console.WriteLine(ex.ToString()); + } + } + + public void DrawFinish() + { + if (_GUISurface != null) + { + GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface); + } + + _GUISurface = null; + } #endregion #region Helpers - protected readonly Dictionary _imageCache = new Dictionary(); - - protected readonly Dictionary _solidBrushes = new Dictionary(); - protected readonly Dictionary _pens = new Dictionary(); - protected SolidBrush GetBrush(Color color) + private readonly Dictionary _imageCache = new Dictionary(); + private readonly Dictionary _solidBrushes = new Dictionary(); + private readonly Dictionary _pens = new Dictionary(); + private SolidBrush GetBrush(Color color) { SolidBrush b; if (!_solidBrushes.TryGetValue(color, out b)) @@ -76,7 +98,7 @@ namespace BizHawk.Client.Common return b; } - protected Pen GetPen(Color color) + private Pen GetPen(Color color) { Pen p; if (!_pens.TryGetValue(color, out p)) @@ -88,7 +110,22 @@ namespace BizHawk.Client.Common return p; } - protected abstract Graphics GetGraphics(); + private Graphics GetGraphics() + { + var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics(); + + // we don't like CoreComm, right? Someone should find a different way to do this then. + var tx = Emulator.CoreComm.ScreenLogicalOffsetX; + var ty = Emulator.CoreComm.ScreenLogicalOffsetY; + if (tx != 0 || ty != 0) + { + var transform = g.Transform; + transform.Translate(-tx, -ty); + g.Transform = transform; + } + + return g; + } public void SetPadding(int all) { _padding = new Padding(all); @@ -97,7 +134,7 @@ namespace BizHawk.Client.Common { _padding = new Padding(x / 2, y / 2, x / 2 + x & 1, y / 2 + y & 1); } - public void SetPadding(int l,int t,int r, int b) + public void SetPadding(int l, int t, int r, int b) { _padding = new Padding(l, t, r, b); } @@ -107,11 +144,21 @@ namespace BizHawk.Client.Common } #endregion - public abstract void AddMessage(string message); + public void AddMessage(string message) + { + GlobalWin.OSD.AddMessage(message); + } - public abstract void ClearGraphics(); + public void ClearGraphics() + { + _GUISurface.Clear(); + DrawFinish(); + } - public abstract void ClearText(); + public void ClearText() + { + GlobalWin.OSD.ClearGUIText(); + } public void SetDefaultForegroundColor(Color color) { @@ -352,7 +399,7 @@ namespace BizHawk.Client.Common { using (var g = GetGraphics()) { - g.CompositingMode = _compositingMode; + g.CompositingMode = _compositingMode; g.DrawLine(GetPen(color ?? _defaultForeground), x1, y1, x2, y2); } } @@ -424,12 +471,13 @@ namespace BizHawk.Client.Common var bg = background ?? _defaultBackground; if (bg.HasValue) { - g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0)); } + g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0)); + } } } - public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null, - string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null) + public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null, + string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null) { using (var g = GetGraphics()) { @@ -508,7 +556,7 @@ namespace BizHawk.Client.Common { for (var yd = -1; yd <= 1; yd++) { - g.DrawString(message, font, GetBrush(bg.Value), x+xd, y+yd); + g.DrawString(message, font, GetBrush(bg.Value), x + xd, y + yd); } } } @@ -522,7 +570,86 @@ namespace BizHawk.Client.Common } } - public abstract void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null); - public abstract void Text(int x, int y, string message, Color? forecolor = null, string anchor = null); + public void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null) + { + using (var g = GetGraphics()) + { + try + { + var index = 0; + if (string.IsNullOrEmpty(fontfamily)) + { + index = _defaultPixelFont; + } + else + { + switch (fontfamily) + { + case "fceux": + case "0": + index = 0; + break; + case "gens": + case "1": + index = 1; + break; + default: + Console.WriteLine($"Unable to find font family: {fontfamily}"); + return; + } + } + + var f = new StringFormat(StringFormat.GenericTypographic) + { + FormatFlags = StringFormatFlags.MeasureTrailingSpaces + }; + var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel); + Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize(); + var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0)); + if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect); + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; + g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y); + } + catch (Exception) + { + return; + } + } + } + + public void Text(int x, int y, string message, Color? forecolor = null, string anchor = null) + { + var a = 0; + + if (!string.IsNullOrEmpty(anchor)) + { + switch (anchor) + { + case "0": + case "topleft": + a = 0; + break; + case "1": + case "topright": + a = 1; + break; + case "2": + case "bottomleft": + a = 2; + break; + case "3": + case "bottomright": + a = 3; + break; + } + } + else + { + x -= Emulator.CoreComm.ScreenLogicalOffsetX; + y -= Emulator.CoreComm.ScreenLogicalOffsetY; + } + + GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a); + } } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs b/BizHawk.Client.EmuHawk/Api/Libraries/InputApi.cs similarity index 92% rename from BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs rename to BizHawk.Client.EmuHawk/Api/Libraries/InputApi.cs index e2e289bae0..56e2cd767f 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Input.cs +++ b/BizHawk.Client.EmuHawk/Api/Libraries/InputApi.cs @@ -3,13 +3,14 @@ using System.Linq; using System.Collections.Generic; using System.Windows.Forms; +using BizHawk.Client.ApiHawk; using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public sealed class InputPluginLibrary : PluginLibraryBase + public sealed class InputApi : IInput { - public InputPluginLibrary() : base() + public InputApi() : base() { } public Dictionary Get() diff --git a/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs b/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs new file mode 100644 index 0000000000..ca44e44a3d --- /dev/null +++ b/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Client.ApiHawk; + +namespace BizHawk.Client.EmuHawk + +{ + public static class ApiManager + { + private static ApiContainer container; + private static void Register(IEmulatorServiceProvider serviceProvider) + { + // Register external apis + var libs = Assembly + .Load("BizHawk.Client.ApiHawk") + .GetTypes() + .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) + .ToList(); + + libs.AddRange( + Assembly + .GetAssembly(typeof(ApiContainer)) + .GetTypes() + .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); + + foreach (var lib in libs) + { + var instance = (IExternalApi)Activator.CreateInstance(lib); + ServiceInjector.UpdateServices(serviceProvider, instance); + Libraries.Add(lib, instance); + } + container = new ApiContainer(Libraries); + GlobalWin.ApiProvider = new BasicApiProvider(container); + } + private static readonly Dictionary Libraries = new Dictionary(); + public static void Restart(IEmulatorServiceProvider newServiceProvider) + { + Libraries.Clear(); + Register(newServiceProvider); + } + } +} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs b/BizHawk.Client.EmuHawk/Api/Libraries/SaveStateAPI.cs similarity index 84% rename from BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs rename to BizHawk.Client.EmuHawk/Api/Libraries/SaveStateAPI.cs index 90f4e5e7f6..df75742920 100644 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Savestate.cs +++ b/BizHawk.Client.EmuHawk/Api/Libraries/SaveStateAPI.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.IO; -using BizHawk.Client.Common; +using BizHawk.Client.ApiHawk; namespace BizHawk.Client.EmuHawk { - public sealed class SavestatePluginibrary : PluginLibraryBase + public sealed class SaveStateApi : ISaveState { - public SavestatePluginibrary() : base() + public SaveStateApi() : base() { } public void Load(string path) diff --git a/BizHawk.Client.EmuHawk/Api/Libraries/ToolApi.cs b/BizHawk.Client.EmuHawk/Api/Libraries/ToolApi.cs new file mode 100644 index 0000000000..d356761cdf --- /dev/null +++ b/BizHawk.Client.EmuHawk/Api/Libraries/ToolApi.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Client.ApiHawk; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class ToolApi : ITool + { + private class ToolStatic + { + public Type GetTool(string name) + { + var toolType = ReflectionUtil.GetTypeByName(name) + .FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface); + + if (toolType != null) + { + GlobalWin.Tools.Load(toolType); + } + + var selectedTool = GlobalWin.Tools.AvailableTools + .FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower()); + + if (selectedTool != null) + { + return selectedTool; + } + + return null; + } + + public object CreateInstance(string name) + { + var possibleTypes = ReflectionUtil.GetTypeByName(name); + + if (possibleTypes.Any()) + { + return Activator.CreateInstance(possibleTypes.First()); + } + + return null; + } + + public static void OpenCheats() + { + GlobalWin.Tools.Load(); + } + + public static void OpenHexEditor() + { + GlobalWin.Tools.Load(); + } + + public static void OpenRamWatch() + { + GlobalWin.Tools.LoadRamWatch(loadDialog: true); + } + + public static void OpenRamSearch() + { + GlobalWin.Tools.Load(); + } + + public static void OpenTasStudio() + { + GlobalWin.Tools.Load(); + } + + public static void OpenToolBox() + { + GlobalWin.Tools.Load(); + } + + public static void OpenTraceLogger() + { + GlobalWin.Tools.Load(); + } + + } + [RequiredService] + private static IEmulator Emulator { get; set; } + + [RequiredService] + private static IVideoProvider VideoProvider { get; set; } + + public ToolApi() + { } + + public Type GetTool(string name) + { + var toolType = ReflectionUtil.GetTypeByName(name) + .FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface); + + if (toolType != null) + { + GlobalWin.Tools.Load(toolType); + } + + var selectedTool = GlobalWin.Tools.AvailableTools + .FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower()); + + if (selectedTool != null) + { + return selectedTool; + } + + return null; + } + + public object CreateInstance(string name) + { + var possibleTypes = ReflectionUtil.GetTypeByName(name); + + if (possibleTypes.Any()) + { + return Activator.CreateInstance(possibleTypes.First()); + } + + return null; + } + + public void OpenCheats() + { + ToolStatic.OpenCheats(); + } + + public void OpenHexEditor() + { + ToolStatic.OpenHexEditor(); + } + + public void OpenRamWatch() + { + ToolStatic.OpenRamWatch(); + } + + public void OpenRamSearch() + { + ToolStatic.OpenRamSearch(); + } + + public void OpenTasStudio() + { + ToolStatic.OpenTasStudio(); + } + + public void OpenToolBox() + { + ToolStatic.OpenToolBox(); + } + + public void OpenTraceLogger() + { + ToolStatic.OpenTraceLogger(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 46f0aa381a..efbb0d391d 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -658,9 +658,14 @@ - - - + + + + + + + + @@ -734,7 +739,6 @@ NameStateForm.cs - Form @@ -747,10 +751,6 @@ PlatformChooser.cs - - - - @@ -1888,7 +1888,6 @@ - diff --git a/BizHawk.Client.EmuHawk/GlobalWin.cs b/BizHawk.Client.EmuHawk/GlobalWin.cs index 5ede6c61fc..06a2bbaab5 100644 --- a/BizHawk.Client.EmuHawk/GlobalWin.cs +++ b/BizHawk.Client.EmuHawk/GlobalWin.cs @@ -1,4 +1,5 @@ using BizHawk.Bizware.BizwareGL; +using BizHawk.Client.ApiHawk; // ReSharper disable StyleCop.SA1401 namespace BizHawk.Client.EmuHawk @@ -7,7 +8,7 @@ namespace BizHawk.Client.EmuHawk { public static MainForm MainForm; public static ToolManager Tools; - public static PluginLibrary Plugins; + public static BasicApiProvider ApiProvider; /// /// the IGL to be used for rendering diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 9fb06ed416..2cc7539c80 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -252,8 +252,6 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Sound.StartSound(); InputManager.RewireInputChain(); GlobalWin.Tools = new ToolManager(this); - GlobalWin.Plugins = new PluginLibrary(Emulator.ServiceProvider); - GlobalWin.Plugins.Load(new Ecco2AssistantPlugin()); RewireSound(); // Workaround for windows, location is -32000 when minimized, if they close it during this time, that's what gets saved @@ -2937,7 +2935,6 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallFrameBeforeEvent(); } - GlobalWin.Plugins.CallFrameBeforeEvent(); if (IsTurboing) { @@ -3024,7 +3021,6 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallFrameAfterEvent(); } - GlobalWin.Plugins.CallFrameAfterEvent(); if (IsTurboing) { @@ -3798,7 +3794,7 @@ namespace BizHawk.Client.EmuHawk } GlobalWin.Tools.Restart(); - GlobalWin.Plugins.Restart(Emulator.ServiceProvider); + ApiManager.Restart(Emulator.ServiceProvider); if (Global.Config.LoadCheatFileByGame) { @@ -3846,7 +3842,7 @@ namespace BizHawk.Client.EmuHawk } } - ClientApi.OnRomLoaded(); + ClientApi.OnRomLoaded(Emulator); return true; } else @@ -3857,10 +3853,11 @@ namespace BizHawk.Client.EmuHawk // The ROM has been loaded by a recursive invocation of the LoadROM method. if (!(Emulator is NullEmulator)) { - ClientApi.OnRomLoaded(); + ClientApi.OnRomLoaded(Emulator); return true; } + ClientApi.UpdateEmulatorAndVP(Emulator); HandlePlatformMenus(); _stateSlots.Clear(); UpdateStatusSlots(); @@ -3950,6 +3947,7 @@ namespace BizHawk.Client.EmuHawk var coreComm = CreateCoreComm(); CoreFileProvider.SyncCoreCommInputSignals(coreComm); Emulator = new NullEmulator(coreComm, Global.Config.GetCoreSettings()); + ClientApi.UpdateEmulatorAndVP(Emulator); Global.ActiveController = new Controller(NullController.Instance.Definition); Global.AutoFireController = _autofireNullControls; RewireSound(); @@ -3972,7 +3970,7 @@ namespace BizHawk.Client.EmuHawk Global.Game = GameInfo.NullInstance; GlobalWin.Tools.Restart(); - GlobalWin.Plugins.Restart(Emulator.ServiceProvider); + ApiManager.Restart(Emulator.ServiceProvider); RewireSound(); Text = "BizHawk" + (VersionInfo.DeveloperBuild ? " (interim) " : ""); HandlePlatformMenus(); @@ -4068,7 +4066,6 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallLoadStateEvent(userFriendlyStateName); } - GlobalWin.Plugins.CallLoadStateEvent(userFriendlyStateName); SetMainformMovieInfo(); GlobalWin.Tools.UpdateToolsBefore(fromLua); @@ -4198,7 +4195,6 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.Tools.LuaConsole.LuaImp.CallSaveStateEvent(quickSlotName); } - GlobalWin.Plugins.CallSaveStateEvent(quickSlotName); } private void SaveStateAs() diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs deleted file mode 100644 index b37d5f37dc..0000000000 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.Client.cs +++ /dev/null @@ -1,351 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using BizHawk.Client.Common; - -namespace BizHawk.Client.EmuHawk -{ - public sealed class EmuHawkPluginLibrary : PluginLibraryBase - { - [RequiredService] - private IEmulator Emulator { get; set; } - - [RequiredService] - private IVideoProvider VideoProvider { get; set; } - - private readonly Dictionary _filterMappings = new Dictionary - { - { 0, "None" }, - { 1, "x2SAI" }, - { 2, "SuperX2SAI" }, - { 3, "SuperEagle" }, - { 4, "Scanlines" }, - }; - - public EmuHawkPluginLibrary() : base() - { } - - public void CloseEmulator() - { - GlobalWin.MainForm.CloseEmulator(); - } - - public void CloseEmulatorWithCode(int exitCode) - { - GlobalWin.MainForm.CloseEmulator(exitCode); - } - - public static int BorderHeight() - { - var point = new System.Drawing.Point(0, 0); - return GlobalWin.DisplayManager.TransformPoint(point).Y; - } - - public static int BorderWidth() - { - var point = new System.Drawing.Point(0, 0); - return GlobalWin.DisplayManager.TransformPoint(point).X; - } - - public int BufferHeight() - { - return VideoProvider.BufferHeight; - } - - public int BufferWidth() - { - return VideoProvider.BufferWidth; - } - - public void ClearAutohold() - { - GlobalWin.MainForm.ClearHolds(); - } - - public static void CloseRom() - { - GlobalWin.MainForm.CloseRom(); - } - - public void EnableRewind(bool enabled) - { - GlobalWin.MainForm.EnableRewind(enabled); - } - - public void FrameSkip(int numFrames) - { - if (numFrames > 0) - { - Global.Config.FrameSkip = numFrames; - GlobalWin.MainForm.FrameSkipMessage(); - } - else - { - Console.WriteLine("Invalid frame skip value"); - } - } - - public static int GetTargetScanlineIntensity() - { - return Global.Config.TargetScanlineFilterIntensity; - } - - public int GetWindowSize() - { - return Global.Config.TargetZoomFactors[Emulator.SystemId]; - } - - public static void SetGameExtraPadding(int left, int top, int right, int bottom) - { - GlobalWin.DisplayManager.GameExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom); - GlobalWin.MainForm.FrameBufferResized(); - } - - public static void SetSoundOn(bool enable) - { - Global.Config.SoundEnabled = enable; - } - - public static bool GetSoundOn() - { - return Global.Config.SoundEnabled; - } - - public static void SetClientExtraPadding(int left, int top, int right, int bottom) - { - GlobalWin.DisplayManager.ClientExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom); - GlobalWin.MainForm.FrameBufferResized(); - } - - public static bool IsPaused() - { - return GlobalWin.MainForm.EmulatorPaused; - } - - public static bool IsTurbo() - { - return GlobalWin.MainForm.IsTurboing; - } - - public static bool IsSeeking() - { - return GlobalWin.MainForm.IsSeeking; - } - - public static void OpenCheats() - { - GlobalWin.Tools.Load(); - } - - public static void OpenHexEditor() - { - GlobalWin.Tools.Load(); - } - - public static void OpenRamWatch() - { - GlobalWin.Tools.LoadRamWatch(loadDialog: true); - } - - public static void OpenRamSearch() - { - GlobalWin.Tools.Load(); - } - - public static void OpenRom(string path) - { - var ioa = OpenAdvancedSerializer.ParseWithLegacy(path); - GlobalWin.MainForm.LoadRom(path, new MainForm.LoadRomArgs { OpenAdvanced = ioa }); - } - - public static void OpenTasStudio() - { - GlobalWin.Tools.Load(); - } - - public static void OpenToolBox() - { - GlobalWin.Tools.Load(); - } - - public static void OpenTraceLogger() - { - GlobalWin.Tools.Load(); - } - - public static void Pause() - { - GlobalWin.MainForm.PauseEmulator(); - } - - public static void PauseAv() - { - GlobalWin.MainForm.PauseAvi = true; - } - - public static void RebootCore() - { - ((LuaConsole)GlobalWin.Tools.Get()).LuaImp.IsRebootingCore = true; - GlobalWin.MainForm.RebootCore(); - ((LuaConsole)GlobalWin.Tools.Get()).LuaImp.IsRebootingCore = false; - } - - public static int ScreenHeight() - { - return GlobalWin.MainForm.PresentationPanel.NativeSize.Height; - } - - public static void Screenshot(string path = null) - { - if (path == null) - { - GlobalWin.MainForm.TakeScreenshot(); - } - else - { - GlobalWin.MainForm.TakeScreenshot(path); - } - } - - public static void ScreenshotToClipboard() - { - GlobalWin.MainForm.TakeScreenshotToClipboard(); - } - - public static void SetTargetScanlineIntensity(int val) - { - Global.Config.TargetScanlineFilterIntensity = val; - } - - public static void SetScreenshotOSD(bool value) - { - Global.Config.Screenshot_CaptureOSD = value; - } - - public static int ScreenWidth() - { - return GlobalWin.MainForm.PresentationPanel.NativeSize.Width; - } - - public void SetWindowSize(int size) - { - if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10) - { - Global.Config.TargetZoomFactors[Emulator.SystemId] = size; - GlobalWin.MainForm.FrameBufferResized(); - GlobalWin.OSD.AddMessage("Window size set to " + size + "x"); - } - else - { - Console.WriteLine("Invalid window size"); - } - } - - public void SpeedMode(int percent) - { - if (percent > 0 && percent < 6400) - { - GlobalWin.MainForm.ClickSpeedItem(percent); - } - else - { - Console.WriteLine("Invalid speed value"); - } - } - - public static void TogglePause() - { - GlobalWin.MainForm.TogglePause(); - } - - public static int TransformPointX(int x) - { - var point = new System.Drawing.Point(x, 0); - return GlobalWin.DisplayManager.TransformPoint(point).X; - } - - public static int TransformPointY(int y) - { - var point = new System.Drawing.Point(0, y); - return GlobalWin.DisplayManager.TransformPoint(point).Y; - } - - public static void Unpause() - { - GlobalWin.MainForm.UnpauseEmulator(); - } - - public static void UnpauseAv() - { - GlobalWin.MainForm.PauseAvi = false; - } - - public static int Xpos() - { - return GlobalWin.MainForm.DesktopLocation.X; - } - - public static int Ypos() - { - return GlobalWin.MainForm.DesktopLocation.Y; - } - - public List GetAvailableTools() - { - var tools = GlobalWin.Tools.AvailableTools.ToList(); - var t = new List(tools.Count); - for (int i = 0; i < tools.Count; i++) - { - t[i] = tools[i].Name.ToLower(); - } - - return t; - } - - public Type GetTool(string name) - { - var toolType = ReflectionUtil.GetTypeByName(name) - .FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface); - - if (toolType != null) - { - GlobalWin.Tools.Load(toolType); - } - - var selectedTool = GlobalWin.Tools.AvailableTools - .FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower()); - - if (selectedTool != null) - { - return selectedTool; - } - - return null; - } - - public object CreateInstance(string name) - { - var possibleTypes = ReflectionUtil.GetTypeByName(name); - - if (possibleTypes.Any()) - { - return Activator.CreateInstance(possibleTypes.First()); - } - - return null; - } - - public void DisplayMessages(bool value) - { - Global.Config.DisplayMessages = value; - } - - public void SaveRam() - { - GlobalWin.MainForm.FlushSaveRAM(); - } - } -} diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs deleted file mode 100644 index e22bd3e0fd..0000000000 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.GUI.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Drawing; - -using BizHawk.Client.Common; - -namespace BizHawk.Client.EmuHawk -{ - public sealed class GUIPluginLibrary : GUIDrawPluginBase - { - public GUIPluginLibrary() : base() - { } - - private DisplaySurface _GUISurface = null; - - #region Gui API - - public override void DrawNew(string name, bool? clear = true) - { - try - { - DrawFinish(); - _GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true); - HasGUISurface = (_GUISurface != null); - - } - catch (InvalidOperationException ex) - { - Console.WriteLine(ex.ToString()); - } - } - - public override void DrawFinish() - { - if (_GUISurface != null) - { - GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface); - } - - _GUISurface = null; - HasGUISurface = false; - - } - #endregion - - #region Helpers - protected override Graphics GetGraphics() - { - var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics(); - - // we don't like CoreComm, right? Someone should find a different way to do this then. - var tx = Emulator.CoreComm.ScreenLogicalOffsetX; - var ty = Emulator.CoreComm.ScreenLogicalOffsetY; - if (tx != 0 || ty != 0) - { - var transform = g.Transform; - transform.Translate(-tx, -ty); - g.Transform = transform; - } - - return g; - } - #endregion - - public override void AddMessage(string message) - { - GlobalWin.OSD.AddMessage(message); - } - - public override void ClearGraphics() - { - _GUISurface.Clear(); - DrawFinish(); - } - - public override void ClearText() - { - GlobalWin.OSD.ClearGUIText(); - } - - public override void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null) - { - using (var g = GetGraphics()) - { - try - { - var index = 0; - if (string.IsNullOrEmpty(fontfamily)) - { - index = _defaultPixelFont; - } - else - { - switch (fontfamily) - { - case "fceux": - case "0": - index = 0; - break; - case "gens": - case "1": - index = 1; - break; - default: - Console.WriteLine($"Unable to find font family: {fontfamily}"); - return; - } - } - - var f = new StringFormat(StringFormat.GenericTypographic) - { - FormatFlags = StringFormatFlags.MeasureTrailingSpaces - }; - var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel); - Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize(); - var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0)); - if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect); - g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; - g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y); - } - catch (Exception) - { - return; - } - } - } - - public override void Text(int x, int y, string message, Color? forecolor = null, string anchor = null) - { - var a = 0; - - if (!string.IsNullOrEmpty(anchor)) - { - switch (anchor) - { - case "0": - case "topleft": - a = 0; - break; - case "1": - case "topright": - a = 1; - break; - case "2": - case "bottomleft": - a = 2; - break; - case "3": - case "bottomright": - a = 3; - break; - } - } - else - { - x -= Emulator.CoreComm.ScreenLogicalOffsetX; - y -= Emulator.CoreComm.ScreenLogicalOffsetY; - } - - GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a); - } - } -} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs b/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs deleted file mode 100644 index 132ba4a2df..0000000000 --- a/BizHawk.Client.EmuHawk/Plugins/Libraries/PluginLibrary.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; - -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; -using BizHawk.Client.Common; - -namespace BizHawk.Client.EmuHawk - -{ - public class PluginLibrary - { -// public LuaDocumentation Docs { get; } - private void Register(IEmulatorServiceProvider serviceProvider) - { - // Docs.Clear(); - - // Register lua libraries - var libs = Assembly - .Load("BizHawk.Client.Common") - .GetTypes() - .Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t)) - .Where(t => t.IsSealed) - .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) - .ToList(); - - libs.AddRange( - Assembly - .GetAssembly(typeof(PluginLibrary)) - .GetTypes() - .Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t)) - .Where(t => t.IsSealed) - .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); - - foreach (var lib in libs) - { - var instance = (PluginLibraryBase)Activator.CreateInstance(lib); - ServiceInjector.UpdateServices(serviceProvider, instance); - Libraries.Add(lib, instance); - } - } - public PluginLibrary(IEmulatorServiceProvider serviceProvider) - { - Register(serviceProvider); - } - private readonly Dictionary Libraries = new Dictionary(); - public List PluginList { get; } = new List(); - - public IEnumerable RunningPlugins - { - get { return PluginList.Where(plug => plug.Enabled); } - } - -// private FormsPluginLibrary FormsLibrary => (FormsLuaLibrary)Libraries[typeof(FormsLuaLibrary)]; -// private EmulatorPluginLibrary EmuPluginLibrary => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)]; - private GUIPluginLibrary GuiLibrary => (GUIPluginLibrary)Libraries[typeof(GUIPluginLibrary)]; - - public void Restart(IEmulatorServiceProvider newServiceProvider) - { - Libraries.Clear(); - Register(newServiceProvider); - foreach (var plugin in PluginList) - { - plugin.Init(new PluginAPI(Libraries)); - } - } - - public void StartPluginDrawing() - { - if (PluginList.Any() && !GuiLibrary.HasGUISurface) - { - GuiLibrary.DrawNew("emu"); - } - } - - public void EndPluginDrawing() - { - if (PluginList.Any()) - { - GuiLibrary.DrawFinish(); - } - } - - public void CallSaveStateEvent(string name) - { - foreach (var plugin in RunningPlugins) plugin.SaveStateCallback(name); - } - - public void CallLoadStateEvent(string name) - { - foreach (var plugin in RunningPlugins) plugin.LoadStateCallback(name); - } - - public void CallFrameBeforeEvent() - { - StartPluginDrawing(); - foreach (var plugin in RunningPlugins) plugin.PreFrameCallback(); - } - - public void CallFrameAfterEvent() - { - foreach (var plugin in RunningPlugins) plugin.PostFrameCallback(); - EndPluginDrawing(); - } - - public void CallExitEvent() - { - foreach (var plugin in RunningPlugins) plugin.ExitCallback(); - } - - public void Close() - { - GuiLibrary.Dispose(); - } - - public void Load(PluginBase plugin) - { - plugin.Init(new PluginAPI(Libraries)); - PluginList.Add(plugin); - } - } -} diff --git a/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs b/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs deleted file mode 100644 index c2e1ea3960..0000000000 --- a/BizHawk.Client.EmuHawk/Plugins/PluginAPI.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Linq; - -using BizHawk.Client.Common; - -namespace BizHawk.Client.EmuHawk -{ - public sealed class PluginAPI : IPluginAPI - { - public EmulatorPluginLibrary EmuLib => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)]; - public GameInfoPluginLibrary GameInfoLib => (GameInfoPluginLibrary)Libraries[typeof(GameInfoPluginLibrary)]; - public GUIDrawPluginBase GUILib => (GUIDrawPluginBase)Libraries[typeof(GUIPluginLibrary)]; - public JoypadPluginLibrary JoypadLib => (JoypadPluginLibrary)Libraries[typeof(JoypadPluginLibrary)]; - public MemoryPluginLibrary MemLib => (MemoryPluginLibrary)Libraries[typeof(MemoryPluginLibrary)]; - public MemoryEventsPluginLibrary MemEventsLib => (MemoryEventsPluginLibrary)Libraries[typeof(MemoryEventsPluginLibrary)]; - public MemorySavestatePluginLibrary MemStateLib => (MemorySavestatePluginLibrary)Libraries[typeof(MemorySavestatePluginLibrary)]; - public MoviePluginLibrary MovieLib => (MoviePluginLibrary)Libraries[typeof(MoviePluginLibrary)]; - public SQLPluginLibrary SQLLib => (SQLPluginLibrary)Libraries[typeof(SQLPluginLibrary)]; - public UserDataPluginLibrary UserDataLib => (UserDataPluginLibrary)Libraries[typeof(UserDataPluginLibrary)]; - public Dictionary Libraries { get; set; } - public PluginAPI(Dictionary libs) - { - Libraries = libs; - } - } -} diff --git a/BizHawk.Client.EmuHawk/tools/ToolBox.cs b/BizHawk.Client.EmuHawk/tools/ToolBox.cs index 503714c6b1..67aefdfd0f 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolBox.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolBox.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Windows.Forms; using BizHawk.Emulation.Common; -using BizHawk.Client.Common; +using BizHawk.Client.ApiHawk; namespace BizHawk.Client.EmuHawk { @@ -66,6 +66,8 @@ namespace BizHawk.Client.EmuHawk continue; if (!ServiceInjector.IsAvailable(Emulator.ServiceProvider, t)) continue; +// if (!ApiInjector.IsAvailable(, t)) +// continue; var instance = Activator.CreateInstance(t); diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 05d530176d..321b301c36 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.ComponentModel; using System.Windows.Forms; +using BizHawk.Client.ApiHawk; using BizHawk.Client.Common; using BizHawk.Emulation.Common; using BizHawk.Common.ReflectionExtensions; @@ -121,6 +122,11 @@ namespace BizHawk.Client.EmuHawk (newTool as Form).Owner = GlobalWin.MainForm; } + if (isExternal) + { + ApiInjector.UpdateApis(GlobalWin.ApiProvider, newTool); + } + ServiceInjector.UpdateServices(Global.Emulator.ServiceProvider, newTool); string toolType = typeof(T).ToString(); @@ -491,6 +497,8 @@ namespace BizHawk.Client.EmuHawk if ((tool.IsHandleCreated && !tool.IsDisposed) || tool is RamWatch) // Hack for RAM Watch - in display watches mode it wants to keep running even closed, it will handle disposed logic { + if (tool is IExternalToolForm) + ApiInjector.UpdateApis(GlobalWin.ApiProvider, tool); tool.Restart(); } } diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 8b9b8cac99..193d86f3fc 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -109,4 +109,4 @@ --> - + \ No newline at end of file From 79aaef02574530972b47dc989dac81abfc373953 Mon Sep 17 00:00:00 2001 From: upthorn Date: Sat, 22 Dec 2018 11:16:54 -0800 Subject: [PATCH 016/440] Removed project references to old, unrefactored files that no longer exist. --- .../BizHawk.Client.Common.csproj | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 84c1eed24d..cee56ac8a8 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -132,21 +132,6 @@ - - - - - - - - - - - - - - - From 3b1fd8fec6d837f2d48215e71edb912bbf011b2e Mon Sep 17 00:00:00 2001 From: upthorn Date: Sat, 22 Dec 2018 11:58:14 -0800 Subject: [PATCH 017/440] Unrename SetExtraPadding methods. --- BizHawk.Client.ApiHawk/Classes/ClientApi.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/BizHawk.Client.ApiHawk/Classes/ClientApi.cs b/BizHawk.Client.ApiHawk/Classes/ClientApi.cs index 8756885f54..19d01f9f08 100644 --- a/BizHawk.Client.ApiHawk/Classes/ClientApi.cs +++ b/BizHawk.Client.ApiHawk/Classes/ClientApi.cs @@ -307,7 +307,7 @@ namespace BizHawk.Client.ApiHawk /// Top padding /// Right padding /// Bottom padding - public static void SetClientExtraPadding(int left, int top, int right, int bottom) + public static void SetExtraPadding(int left, int top, int right, int bottom) { FieldInfo f = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin").GetField("DisplayManager"); object displayManager = f.GetValue(null); @@ -321,9 +321,9 @@ namespace BizHawk.Client.ApiHawk /// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements /// /// Left padding - public static void SetClientExtraPadding(int left) + public static void SetExtraPadding(int left) { - SetClientExtraPadding(left, 0, 0, 0); + SetExtraPadding(left, 0, 0, 0); } /// @@ -331,9 +331,9 @@ namespace BizHawk.Client.ApiHawk /// /// Left padding /// Top padding - public static void SetClientExtraPadding(int left, int top) + public static void SetExtraPadding(int left, int top) { - SetClientExtraPadding(left, top, 0, 0); + SetExtraPadding(left, top, 0, 0); } /// @@ -342,12 +342,11 @@ namespace BizHawk.Client.ApiHawk /// Left padding /// Top padding /// Right padding - public static void SetClientExtraPadding(int left, int top, int right) + public static void SetExtraPadding(int left, int top, int right) { - SetClientExtraPadding(left, top, right, 0); + SetExtraPadding(left, top, right, 0); } - /// /// Set inputs in specified to specified player /// From b9d35399b7b75b7dd7ce451488c0265080875097 Mon Sep 17 00:00:00 2001 From: upthorn Date: Sun, 23 Dec 2018 00:46:20 -0800 Subject: [PATCH 018/440] Created some working small integers to bypass C#'s hatred of 8bit and 16bit arithmetic. --- .../BizHawk.Emulation.Common.csproj | 4 + .../WorkingTypes/wbyte.cs | 112 ++++++++++++++++++ .../WorkingTypes/wsbyte.cs | 111 +++++++++++++++++ .../WorkingTypes/wshort.cs | 111 +++++++++++++++++ .../WorkingTypes/wushort.cs | 112 ++++++++++++++++++ 5 files changed, 450 insertions(+) create mode 100644 BizHawk.Emulation.Common/WorkingTypes/wbyte.cs create mode 100644 BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs create mode 100644 BizHawk.Emulation.Common/WorkingTypes/wshort.cs create mode 100644 BizHawk.Emulation.Common/WorkingTypes/wushort.cs diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index 0a8aa6ec09..7287faab8b 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -121,6 +121,10 @@ + + + + diff --git a/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs new file mode 100644 index 0000000000..f09a152bd6 --- /dev/null +++ b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs @@ -0,0 +1,112 @@ +using System; +using System.Globalization; +using System.Security; + + +namespace BizHawk.Emulation.Common.WorkingTypes +{ + // + // Summary: + // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# Byte by calling its methods where relevant. + public unsafe class wbyte : IComparable, IFormattable, IComparable, IEquatable + { + private Byte val; + public const Byte MaxValue = Byte.MaxValue; + public const Byte MinValue = Byte.MinValue; + public static implicit operator wbyte(uint value) + { + return value; + } + public static implicit operator byte(wbyte value) + { + return value.val; + } + public wbyte() + { + + } + public wbyte(uint value) + { + val = (Byte)(value & 0xFF); + } + public wbyte(int value) + { + val = (Byte)(value & 0xFF); + } + public wbyte(double value) + { + val = (Byte)(((int)value) & 0xFF); + } + public static wbyte Parse(string s, NumberStyles style, IFormatProvider provider) + { + return (uint)Byte.Parse(s, style, provider); + } + public static wbyte Parse(string s, IFormatProvider provider) + { + return (uint)Byte.Parse(s, provider); + } + public static wbyte Parse(string s) + { + return (uint)Byte.Parse(s); + } + public static wbyte Parse(string s, NumberStyles style) + { + return (uint)Byte.Parse(s, style); + } + public static bool TryParse(string s, out wbyte result) + { + result = new wbyte(); + return byte.TryParse(s, out result.val); + } + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wbyte result) + { + result = new wbyte(); + return byte.TryParse(s, style, provider, out result.val); + } + public int CompareTo(wbyte value) + { + return val.CompareTo(value.val); + } + public int CompareTo(object value) + { + return val.CompareTo(value); + } + public override bool Equals(object obj) + { + return val.Equals(obj); + } + public bool Equals(wbyte obj) + { + return val.Equals(obj); + } + public override int GetHashCode() + { + return val.GetHashCode(); + } + public TypeCode GetTypeCode() + { + return val.GetTypeCode(); + } + [SecuritySafeCritical] + public string ToString(string format, IFormatProvider provider) + { + return val.ToString(format, provider); + } + [SecuritySafeCritical] + public override string ToString() + { + return val.ToString(); + } + [SecuritySafeCritical] + public string ToString(string format) + { + return val.ToString(format); + } + [SecuritySafeCritical] + public string ToString(IFormatProvider provider) + { + return val.ToString(provider); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs new file mode 100644 index 0000000000..859b0a563c --- /dev/null +++ b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs @@ -0,0 +1,111 @@ +using System; +using System.Globalization; +using System.Security; + +namespace BizHawk.Emulation.Common.WorkingTypes +{ + // + // Summary: + // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# SByte by calling its methods where relevant. + public unsafe class wsbyte : IComparable, IFormattable, IComparable, IEquatable + { + private SByte val; + public const SByte MaxValue = SByte.MaxValue; + public const SByte MinValue = SByte.MinValue; + public static implicit operator wsbyte(int value) + { + return value; + } + public static implicit operator SByte(wsbyte value) + { + return value.val; + } + public wsbyte() + { + + } + public wsbyte(int value) + { + val = (SByte)(value & 0xFF); + } + public wsbyte(uint value) + { + val = (SByte)(value & 0xFF); + } + public wsbyte(double value) + { + val = (SByte)(((uint)value) & 0xFF); + } + public static wsbyte Parse(string s, NumberStyles style, IFormatProvider provider) + { + return (int)SByte.Parse(s, style, provider); + } + public static wsbyte Parse(string s, IFormatProvider provider) + { + return (int)SByte.Parse(s, provider); + } + public static wsbyte Parse(string s) + { + return (int)SByte.Parse(s); + } + public static wsbyte Parse(string s, NumberStyles style) + { + return (int)SByte.Parse(s, style); + } + public static bool TryParse(string s, out wsbyte result) + { + result = new wsbyte(); + return SByte.TryParse(s, out result.val); + } + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wsbyte result) + { + result = new wsbyte(); + return SByte.TryParse(s, style, provider, out result.val); + } + public int CompareTo(wsbyte value) + { + return val.CompareTo(value.val); + } + public int CompareTo(object value) + { + return val.CompareTo(value); + } + public override bool Equals(object obj) + { + return val.Equals(obj); + } + public bool Equals(wsbyte obj) + { + return val.Equals(obj); + } + public override int GetHashCode() + { + return val.GetHashCode(); + } + public TypeCode GetTypeCode() + { + return val.GetTypeCode(); + } + [SecuritySafeCritical] + public string ToString(string format, IFormatProvider provider) + { + return val.ToString(format, provider); + } + [SecuritySafeCritical] + public override string ToString() + { + return val.ToString(); + } + [SecuritySafeCritical] + public string ToString(string format) + { + return val.ToString(format); + } + [SecuritySafeCritical] + public string ToString(IFormatProvider provider) + { + return val.ToString(provider); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Common/WorkingTypes/wshort.cs b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs new file mode 100644 index 0000000000..04040691b9 --- /dev/null +++ b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs @@ -0,0 +1,111 @@ +using System; +using System.Globalization; +using System.Security; + +namespace BizHawk.Emulation.Common.WorkingTypes +{ + // + // Summary: + // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# Int16 by calling its methods where relevant. + public unsafe class wshort : IComparable, IFormattable, IComparable, IEquatable + { + private Int16 val; + public const Int16 MaxValue = Int16.MaxValue; + public const Int16 MinValue = Int16.MinValue; + public static implicit operator wshort(int value) + { + return value; + } + public static implicit operator Int16(wshort value) + { + return value.val; + } + public wshort() + { + + } + public wshort(int value) + { + val = (Int16)(value & 0xFFFF); + } + public wshort(uint value) + { + val = (Int16)(value & 0xFFFF); + } + public wshort(double value) + { + val = (Int16)(((uint)value) & 0xFFFF); + } + public static wshort Parse(string s, NumberStyles style, IFormatProvider provider) + { + return (int)Int16.Parse(s, style, provider); + } + public static wshort Parse(string s, IFormatProvider provider) + { + return (int)Int16.Parse(s, provider); + } + public static wshort Parse(string s) + { + return (int)Int16.Parse(s); + } + public static wshort Parse(string s, NumberStyles style) + { + return (int)Int16.Parse(s, style); + } + public static bool TryParse(string s, out wshort result) + { + result = new wshort(); + return Int16.TryParse(s, out result.val); + } + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wshort result) + { + result = new wshort(); + return Int16.TryParse(s, style, provider, out result.val); + } + public int CompareTo(wshort value) + { + return val.CompareTo(value.val); + } + public int CompareTo(object value) + { + return val.CompareTo(value); + } + public override bool Equals(object obj) + { + return val.Equals(obj); + } + public bool Equals(wshort obj) + { + return val.Equals(obj); + } + public override int GetHashCode() + { + return val.GetHashCode(); + } + public TypeCode GetTypeCode() + { + return val.GetTypeCode(); + } + [SecuritySafeCritical] + public string ToString(string format, IFormatProvider provider) + { + return val.ToString(format, provider); + } + [SecuritySafeCritical] + public override string ToString() + { + return val.ToString(); + } + [SecuritySafeCritical] + public string ToString(string format) + { + return val.ToString(format); + } + [SecuritySafeCritical] + public string ToString(IFormatProvider provider) + { + return val.ToString(provider); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Common/WorkingTypes/wushort.cs b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs new file mode 100644 index 0000000000..3e5a84abe3 --- /dev/null +++ b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs @@ -0,0 +1,112 @@ +using System; +using System.Globalization; +using System.Security; + + +namespace BizHawk.Emulation.Common.WorkingTypes +{ + // + // Summary: + // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# UInt16 by calling its methods where relevant. + public unsafe class wushort : IComparable, IFormattable, IComparable, IEquatable + { + private UInt16 val; + public const UInt16 MaxValue = UInt16.MaxValue; + public const UInt16 MinValue = UInt16.MinValue; + public static implicit operator wushort(uint value) + { + return value; + } + public static implicit operator ushort(wushort value) + { + return value.val; + } + public wushort() + { + + } + public wushort(uint value) + { + val = (UInt16)(value & 0xFFFF); + } + public wushort(int value) + { + val = (UInt16)(value & 0xFFFF); + } + public wushort(double value) + { + val = (UInt16)(((int)value) & 0xFFFF); + } + public static wushort Parse(string s, NumberStyles style, IFormatProvider provider) + { + return (uint)UInt16.Parse(s, style, provider); + } + public static wushort Parse(string s, IFormatProvider provider) + { + return (uint)UInt16.Parse(s, provider); + } + public static wushort Parse(string s) + { + return (uint)UInt16.Parse(s); + } + public static wushort Parse(string s, NumberStyles style) + { + return (uint)UInt16.Parse(s, style); + } + public static bool TryParse(string s, out wushort result) + { + result = new wushort(); + return ushort.TryParse(s, out result.val); + } + public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wushort result) + { + result = new wushort(); + return ushort.TryParse(s, style, provider, out result.val); + } + public int CompareTo(wushort value) + { + return val.CompareTo(value.val); + } + public int CompareTo(object value) + { + return val.CompareTo(value); + } + public override bool Equals(object obj) + { + return val.Equals(obj); + } + public bool Equals(wushort obj) + { + return val.Equals(obj); + } + public override int GetHashCode() + { + return val.GetHashCode(); + } + public TypeCode GetTypeCode() + { + return val.GetTypeCode(); + } + [SecuritySafeCritical] + public string ToString(string format, IFormatProvider provider) + { + return val.ToString(format, provider); + } + [SecuritySafeCritical] + public override string ToString() + { + return val.ToString(); + } + [SecuritySafeCritical] + public string ToString(string format) + { + return val.ToString(format); + } + [SecuritySafeCritical] + public string ToString(IFormatProvider provider) + { + return val.ToString(provider); + } + } +} \ No newline at end of file From 34c207ff38e689dce820f8fb0c4b9fea7f4b9a84 Mon Sep 17 00:00:00 2001 From: upthorn Date: Sun, 23 Dec 2018 04:25:08 -0800 Subject: [PATCH 019/440] Fixed an infinite recursion in the implicit conversions of the working types --- BizHawk.Emulation.Common/WorkingTypes/wbyte.cs | 2 +- BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs | 2 +- BizHawk.Emulation.Common/WorkingTypes/wshort.cs | 2 +- BizHawk.Emulation.Common/WorkingTypes/wushort.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs index f09a152bd6..aeabe1ffd6 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Common.WorkingTypes public const Byte MinValue = Byte.MinValue; public static implicit operator wbyte(uint value) { - return value; + return new wbyte(value); } public static implicit operator byte(wbyte value) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs index 859b0a563c..183f4af48e 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Common.WorkingTypes public const SByte MinValue = SByte.MinValue; public static implicit operator wsbyte(int value) { - return value; + return new wsbyte(value); } public static implicit operator SByte(wsbyte value) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wshort.cs b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs index 04040691b9..7e0808471f 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wshort.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Common.WorkingTypes public const Int16 MinValue = Int16.MinValue; public static implicit operator wshort(int value) { - return value; + return new wshort(value); } public static implicit operator Int16(wshort value) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wushort.cs b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs index 3e5a84abe3..57851100b6 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wushort.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Common.WorkingTypes public const UInt16 MinValue = UInt16.MinValue; public static implicit operator wushort(uint value) { - return value; + return new wushort(value); } public static implicit operator ushort(wushort value) { From c76d850687f320cafa6b174b6af98fedd3a63d3f Mon Sep 17 00:00:00 2001 From: upthorn Date: Thu, 3 Jan 2019 05:52:31 -0800 Subject: [PATCH 020/440] Working types now allow implicit conversions from longs. --- .../Api/Libraries/PluginLibrary.cs | 52 ------------------- .../WorkingTypes/wbyte.cs | 24 +++++---- .../WorkingTypes/wsbyte.cs | 20 +++---- .../WorkingTypes/wshort.cs | 20 +++---- .../WorkingTypes/wushort.cs | 18 ++++--- 5 files changed, 45 insertions(+), 89 deletions(-) delete mode 100644 BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs diff --git a/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs b/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs deleted file mode 100644 index ca44e44a3d..0000000000 --- a/BizHawk.Client.EmuHawk/Api/Libraries/PluginLibrary.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; - -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; -using BizHawk.Client.ApiHawk; - -namespace BizHawk.Client.EmuHawk - -{ - public static class ApiManager - { - private static ApiContainer container; - private static void Register(IEmulatorServiceProvider serviceProvider) - { - // Register external apis - var libs = Assembly - .Load("BizHawk.Client.ApiHawk") - .GetTypes() - .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) - .Where(t => t.IsSealed) - .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) - .ToList(); - - libs.AddRange( - Assembly - .GetAssembly(typeof(ApiContainer)) - .GetTypes() - .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) - .Where(t => t.IsSealed) - .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); - - foreach (var lib in libs) - { - var instance = (IExternalApi)Activator.CreateInstance(lib); - ServiceInjector.UpdateServices(serviceProvider, instance); - Libraries.Add(lib, instance); - } - container = new ApiContainer(Libraries); - GlobalWin.ApiProvider = new BasicApiProvider(container); - } - private static readonly Dictionary Libraries = new Dictionary(); - public static void Restart(IEmulatorServiceProvider newServiceProvider) - { - Libraries.Clear(); - Register(newServiceProvider); - } - } -} diff --git a/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs index aeabe1ffd6..621ea82131 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wbyte.cs @@ -7,14 +7,18 @@ namespace BizHawk.Emulation.Common.WorkingTypes { // // Summary: - // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. - // Also provides all the base functionality of the standard C# Byte by calling its methods where relevant. + // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# Byte by calling its methods where relevant. public unsafe class wbyte : IComparable, IFormattable, IComparable, IEquatable { private Byte val; public const Byte MaxValue = Byte.MaxValue; public const Byte MinValue = Byte.MinValue; - public static implicit operator wbyte(uint value) + public static implicit operator wbyte(ulong value) + { + return new wbyte(value); + } + public static implicit operator wbyte(wushort value) { return new wbyte(value); } @@ -26,33 +30,33 @@ namespace BizHawk.Emulation.Common.WorkingTypes { } - public wbyte(uint value) + public wbyte(ulong value) { val = (Byte)(value & 0xFF); } - public wbyte(int value) + public wbyte(long value) { val = (Byte)(value & 0xFF); } public wbyte(double value) { - val = (Byte)(((int)value) & 0xFF); + val = (Byte)(((long)value) & 0xFF); } public static wbyte Parse(string s, NumberStyles style, IFormatProvider provider) { - return (uint)Byte.Parse(s, style, provider); + return (ulong)Byte.Parse(s, style, provider); } public static wbyte Parse(string s, IFormatProvider provider) { - return (uint)Byte.Parse(s, provider); + return (ulong)Byte.Parse(s, provider); } public static wbyte Parse(string s) { - return (uint)Byte.Parse(s); + return (ulong)Byte.Parse(s); } public static wbyte Parse(string s, NumberStyles style) { - return (uint)Byte.Parse(s, style); + return (ulong)Byte.Parse(s, style); } public static bool TryParse(string s, out wbyte result) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs index 183f4af48e..187cf46c39 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wsbyte.cs @@ -6,14 +6,14 @@ namespace BizHawk.Emulation.Common.WorkingTypes { // // Summary: - // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. - // Also provides all the base functionality of the standard C# SByte by calling its methods where relevant. + // Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# SByte by calling its methods where relevant. public unsafe class wsbyte : IComparable, IFormattable, IComparable, IEquatable { private SByte val; public const SByte MaxValue = SByte.MaxValue; public const SByte MinValue = SByte.MinValue; - public static implicit operator wsbyte(int value) + public static implicit operator wsbyte(long value) { return new wsbyte(value); } @@ -25,33 +25,33 @@ namespace BizHawk.Emulation.Common.WorkingTypes { } - public wsbyte(int value) + public wsbyte(long value) { val = (SByte)(value & 0xFF); } - public wsbyte(uint value) + public wsbyte(ulong value) { val = (SByte)(value & 0xFF); } public wsbyte(double value) { - val = (SByte)(((uint)value) & 0xFF); + val = (SByte)(((ulong)value) & 0xFF); } public static wsbyte Parse(string s, NumberStyles style, IFormatProvider provider) { - return (int)SByte.Parse(s, style, provider); + return (long)SByte.Parse(s, style, provider); } public static wsbyte Parse(string s, IFormatProvider provider) { - return (int)SByte.Parse(s, provider); + return (long)SByte.Parse(s, provider); } public static wsbyte Parse(string s) { - return (int)SByte.Parse(s); + return (long)SByte.Parse(s); } public static wsbyte Parse(string s, NumberStyles style) { - return (int)SByte.Parse(s, style); + return (long)SByte.Parse(s, style); } public static bool TryParse(string s, out wsbyte result) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wshort.cs b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs index 7e0808471f..aa66438db3 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wshort.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wshort.cs @@ -6,14 +6,14 @@ namespace BizHawk.Emulation.Common.WorkingTypes { // // Summary: - // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. - // Also provides all the base functionality of the standard C# Int16 by calling its methods where relevant. + // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# Int16 by calling its methods where relevant. public unsafe class wshort : IComparable, IFormattable, IComparable, IEquatable { private Int16 val; public const Int16 MaxValue = Int16.MaxValue; public const Int16 MinValue = Int16.MinValue; - public static implicit operator wshort(int value) + public static implicit operator wshort(long value) { return new wshort(value); } @@ -25,33 +25,33 @@ namespace BizHawk.Emulation.Common.WorkingTypes { } - public wshort(int value) + public wshort(long value) { val = (Int16)(value & 0xFFFF); } - public wshort(uint value) + public wshort(ulong value) { val = (Int16)(value & 0xFFFF); } public wshort(double value) { - val = (Int16)(((uint)value) & 0xFFFF); + val = (Int16)(((ulong)value) & 0xFFFF); } public static wshort Parse(string s, NumberStyles style, IFormatProvider provider) { - return (int)Int16.Parse(s, style, provider); + return (long)Int16.Parse(s, style, provider); } public static wshort Parse(string s, IFormatProvider provider) { - return (int)Int16.Parse(s, provider); + return (long)Int16.Parse(s, provider); } public static wshort Parse(string s) { - return (int)Int16.Parse(s); + return (long)Int16.Parse(s); } public static wshort Parse(string s, NumberStyles style) { - return (int)Int16.Parse(s, style); + return (long)Int16.Parse(s, style); } public static bool TryParse(string s, out wshort result) { diff --git a/BizHawk.Emulation.Common/WorkingTypes/wushort.cs b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs index 57851100b6..427a414c6f 100644 --- a/BizHawk.Emulation.Common/WorkingTypes/wushort.cs +++ b/BizHawk.Emulation.Common/WorkingTypes/wushort.cs @@ -7,18 +7,22 @@ namespace BizHawk.Emulation.Common.WorkingTypes { // // Summary: - // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. - // Also provides all the base functionality of the standard C# UInt16 by calling its methods where relevant. + // Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep. + // Also provides all the base functionality of the standard C# UInt16 by calling its methods where relevant. public unsafe class wushort : IComparable, IFormattable, IComparable, IEquatable { private UInt16 val; public const UInt16 MaxValue = UInt16.MaxValue; public const UInt16 MinValue = UInt16.MinValue; - public static implicit operator wushort(uint value) + public static implicit operator wushort(ulong value) { return new wushort(value); } - public static implicit operator ushort(wushort value) + public static implicit operator wushort(wbyte value) + { + return new wushort(value); + } + public static implicit operator UInt16(wushort value) { return value.val; } @@ -26,17 +30,17 @@ namespace BizHawk.Emulation.Common.WorkingTypes { } - public wushort(uint value) + public wushort(ulong value) { val = (UInt16)(value & 0xFFFF); } - public wushort(int value) + public wushort(long value) { val = (UInt16)(value & 0xFFFF); } public wushort(double value) { - val = (UInt16)(((int)value) & 0xFFFF); + val = (UInt16)(((long)value) & 0xFFFF); } public static wushort Parse(string s, NumberStyles style, IFormatProvider provider) { From bc4330a9d1df1ed8cf84fa1ce4b5bbe1a86b1e44 Mon Sep 17 00:00:00 2001 From: upthorn Date: Thu, 3 Jan 2019 05:53:26 -0800 Subject: [PATCH 021/440] External tools no longer crash on loading new ROM --- BizHawk.Client.EmuHawk/Api/ApiManager.cs | 52 +++++++++++++++++++ .../BizHawk.Client.EmuHawk.csproj | 2 +- BizHawk.Client.EmuHawk/MainForm.cs | 2 +- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/Api/ApiManager.cs diff --git a/BizHawk.Client.EmuHawk/Api/ApiManager.cs b/BizHawk.Client.EmuHawk/Api/ApiManager.cs new file mode 100644 index 0000000000..9dd5b71087 --- /dev/null +++ b/BizHawk.Client.EmuHawk/Api/ApiManager.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Client.ApiHawk; + +namespace BizHawk.Client.EmuHawk + +{ + public static class ApiManager + { + private static ApiContainer container; + private static void Register(IEmulatorServiceProvider serviceProvider) + { + // Register external apis + var apis = Assembly + .Load("BizHawk.Client.ApiHawk") + .GetTypes() + .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) + .ToList(); + + apis.AddRange( + Assembly + .GetAssembly(typeof(ApiContainer)) + .GetTypes() + .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); + + foreach (var api in apis) + { + var instance = (IExternalApi)Activator.CreateInstance(api); + ServiceInjector.UpdateServices(serviceProvider, instance); + Libraries.Add(api, instance); + } + container = new ApiContainer(Libraries); + GlobalWin.ApiProvider = new BasicApiProvider(container); + } + private static readonly Dictionary Libraries = new Dictionary(); + public static void Restart(IEmulatorServiceProvider newServiceProvider) + { + Libraries.Clear(); + Register(newServiceProvider); + } + } +} diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index efbb0d391d..e149f0bf88 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -664,7 +664,7 @@ - + diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 626e98fe2b..5ac22ab9f3 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3793,8 +3793,8 @@ namespace BizHawk.Client.EmuHawk } } - GlobalWin.Tools.Restart(); ApiManager.Restart(Emulator.ServiceProvider); + GlobalWin.Tools.Restart(); if (Global.Config.LoadCheatFileByGame) { From f47c2d15588be661fde2a2b66dd0edbd47027364 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 12:10:53 -0600 Subject: [PATCH 022/440] GBHawk: Start link support --- BizHawk.Client.Common/RomLoader.cs | 19 +- .../BizHawk.Emulation.Cores.csproj | 25 +++ .../Nintendo/GBHawk/GBHawk.IEmulator.cs | 2 +- .../Nintendo/GBHawk/GBHawk.IStatable.cs | 4 +- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 3 +- .../GBHawkLink/GBHawkLink.ICodeDataLog.cs | 186 ++++++++++++++++++ .../GBHawkLink/GBHawkLink.IDebuggable.cs | 77 ++++++++ .../GBHawkLink/GBHawkLink.IEmulator.cs | 128 ++++++++++++ .../GBHawkLink/GBHawkLink.IInputPollable.cs | 24 +++ .../GBHawkLink/GBHawkLink.IMemoryDomains.cs | 129 ++++++++++++ .../GBHawkLink/GBHawkLink.ISaveRam.cs | 34 ++++ .../GBHawkLink/GBHawkLink.ISettable.cs | 91 +++++++++ .../GBHawkLink/GBHawkLink.IStatable.cs | 63 ++++++ .../Nintendo/GBHawkLink/GBHawkLink.cs | 88 +++++++++ .../GBHawkLink/GBHawkLinkControllerDeck.cs | 84 ++++++++ .../GBHawkLink/GBHawkLinkControllers.cs | 94 +++++++++ .../Consoles/Nintendo/GBHawkLink/ReadMe.txt | 1 + 17 files changed, 1044 insertions(+), 8 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index ef007eeac6..3a4b1d69a6 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -14,6 +14,7 @@ using BizHawk.Emulation.Cores.Computers.Commodore64; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.Nintendo.GBHawk; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.Sega.Saturn; @@ -630,7 +631,20 @@ namespace BizHawk.Client.Common var left = Database.GetGameInfo(leftBytes, "left.gb"); var right = Database.GetGameInfo(rightBytes, "right.gb"); - nextEmulator = new GambatteLink( + if (Global.Config.GB_UseGBHawk) + { + nextEmulator = new GBHawkLink( + nextComm, + left, + leftBytes, + right, + rightBytes, + GetCoreSettings(), + GetCoreSyncSettings()); + } + else + { + nextEmulator = new GambatteLink( nextComm, left, leftBytes, @@ -639,7 +653,8 @@ namespace BizHawk.Client.Common GetCoreSettings(), GetCoreSyncSettings(), Deterministic); - + } + // other stuff todo break; case "AppleII": diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index f57d61d6eb..744a7d8c27 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -789,6 +789,31 @@ VBANext.cs + + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index be2812ef86..01f04f8338 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } ticker++; - //if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } + // if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } in_vblank_old = in_vblank; REG_FF0F_OLD = REG_FF0F; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs index 161f06c92d..5091c6ceb8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs @@ -107,9 +107,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("cart_RAM", ref cart_RAM, false); } - - - ser.EndSection(); + ser.EndSection(); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index d7c8edcf4f..00e89a039e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -3,7 +3,6 @@ using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.Components.LR35902; -using BizHawk.Common.NumberExtensions; using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; using System.Runtime.InteropServices; @@ -275,7 +274,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private readonly GBHawkControllerDeck _controllerDeck; - private void HardReset() + public void HardReset() { GB_bios_register = 0; // bios enable GBC_compat = is_GBC; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs new file mode 100644 index 0000000000..cfc841d321 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs @@ -0,0 +1,186 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.LR35902; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : ICodeDataLogger + { + private ICodeDataLog _cdl; + + public void SetCDL(ICodeDataLog cdl) + { + _cdl = cdl; + if (cdl == null) + this.L.cpu.CDLCallback = null; + else this.L.cpu.CDLCallback = CDLCpuCallback; + } + + public void NewCDL(ICodeDataLog cdl) + { + cdl["ROM"] = new byte[MemoryDomains["ROM L"].Size]; + cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM L"].Size]; + + cdl["WRAM"] = new byte[MemoryDomains["Main RAM L"].Size]; + + if (MemoryDomains.Has("Cart RAM L")) + { + cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM L"].Size]; + } + + cdl.SubType = "GB"; + cdl.SubVer = 0; + } + + [FeatureNotImplemented] + void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl) + { + } + + public void SetCDL(LR35902.eCDLogMemFlags flags, string type, int cdladdr) + { + if (type == null) return; + byte val = (byte)flags; + _cdl[type][cdladdr] |= (byte)flags; + } + + void CDLCpuCallback(ushort addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + //don't record writes to the ROM, it's just noisy + //NOTE: in principle a mapper could mount a useful resource here, but I doubt it) + if ((flags & LR35902.eCDLogMemFlags.Write) != 0) return; + } + + if (L.ppu.DMA_start) + { + // some of gekkio's tests require these to be accessible during DMA + if (addr < 0x8000) + { + if (L.ppu.DMA_addr < 0x80) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if ((addr >= 0xE000) && (addr < 0xF000)) + { + SetCDL(flags, "WRAM", addr - 0xE000); + } + else if ((addr >= 0xF000) && (addr < 0xFE00)) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000)); + } + else if ((addr >= 0xFE00) && (addr < 0xFEA0) && L.ppu.DMA_OAM_access) + { + return; + } + else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible + { + return; + } + else if ((addr >= 0xFF80)) + { + SetCDL(flags, "HRAM", addr - 0xFF80); + } + + } + + if (addr < 0x900) + { + if (addr < 0x100) + { + // return Either BIOS ROM or Game ROM + if ((L.GB_bios_register & 0x1) == 0) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if (addr >= 0x200) + { + // return Either BIOS ROM or Game ROM + if (((L.GB_bios_register & 0x1) == 0) && L.is_GBC) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if (addr < 0x8000) + { + L.mapper.MapCDL(addr, flags); + return; + } + else if (addr < 0xA000) + { + return; + } + else if (addr < 0xC000) + { + L.mapper.MapCDL(addr, flags); + return; + } + else if (addr < 0xD000) + { + return; + } + else if (addr < 0xE000) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xD000)); + } + else if (addr < 0xF000) + { + SetCDL(flags, "WRAM", addr - 0xE000); + } + else if (addr < 0xFE00) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000)); + } + else if (addr < 0xFEA0) + { + return; + } + else if (addr < 0xFF00) + { + return; + } + else if (addr < 0xFF80) + { + return; + } + else if (addr < 0xFFFF) + { + SetCDL(flags, "HRAM", addr - 0xFF80); + } + else + { + return; + } + + } + + + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs new file mode 100644 index 0000000000..e9b191d02a --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + return new Dictionary + { + /* + ["A"] = cpu.A, + ["X"] = cpu.X, + ["Y"] = cpu.Y, + ["S"] = cpu.S, + ["PC"] = cpu.PC, + ["Flag C"] = cpu.FlagC, + ["Flag Z"] = cpu.FlagZ, + ["Flag I"] = cpu.FlagI, + ["Flag D"] = cpu.FlagD, + ["Flag B"] = cpu.FlagB, + ["Flag V"] = cpu.FlagV, + ["Flag N"] = cpu.FlagN, + ["Flag T"] = cpu.FlagT + */ + }; + } + + public void SetCpuRegister(string register, int value) + { + switch (register) + { + default: + throw new InvalidOperationException(); + case "A": + //cpu.A = (byte)value; + break; + case "X": + //cpu.X = (byte)value; + break; + case "Y": + //cpu.Y = (byte)value; + break; + case "S": + //cpu.S = (byte)value; + break; + case "PC": + //cpu.PC = (ushort)value; + break; + case "Flag I": + //cpu.FlagI = value > 0; + break; + } + } + + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); + + public bool CanStep(StepType type) + { + return false; + } + + [FeatureNotImplemented] + public void Step(StepType type) + { + throw new NotImplementedException(); + } + + public long TotalExecutedCycles + { + get { return (long)L.cpu.TotalExecutedCycles; } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs new file mode 100644 index 0000000000..790ab1fa06 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -0,0 +1,128 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IEmulator, IVideoProvider + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + + public byte controller_state; + public bool in_vblank_old; + public bool in_vblank; + public bool vblank_rise; + + public void FrameAdvance(IController controller, bool render, bool rendersound) + { + //Console.WriteLine("-----------------------FRAME-----------------------"); + if (_tracer.Enabled) + { + L.cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + L.cpu.TraceCallback = null; + } + + _frame++; + + if (controller.IsPressed("Power")) + { + HardReset(); + } + + _islag = true; + + GetControllerState(controller); + + do_frame(); + + _islag = L._islag; + + if (_islag) + { + _lagcount++; + } + } + + public void do_frame() + { + L.do_frame(); + R.do_frame(); + } + + public void GetControllerState(IController controller) + { + InputCallbacks.Call(); + L.controller_state = _controllerDeck.ReadPort1(controller); + R.controller_state = _controllerDeck.ReadPort2(controller); + } + + public int Frame => _frame; + + public string SystemId => "GB"; + + public bool DeterministicEmulation { get; set; } + + public void ResetCounters() + { + _frame = 0; + _lagcount = 0; + _islag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + L.Dispose(); + R.Dispose(); + } + + #region Video provider + + public int _frameHz = 60; + + public int[] _vidbuffer = new int[160 * 2 * 144]; + public int[] buff_L; + public int[] buff_R; + + public int[] GetVideoBuffer() + { + // combine the 2 video buffers from the instances + buff_L = L.GetVideoBuffer(); + buff_R = R.GetVideoBuffer(); + + for (int i = 0; i < 144; i++) + { + for (int j = 0; j < 160; j++) + { + _vidbuffer[i * 320 + j] = buff_L[i * 160 + j]; + _vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j]; + } + } + + return _vidbuffer; + } + + public int VirtualWidth => 160 * 2; + public int VirtualHeight => 144; + public int BufferWidth => 160 * 2; + public int BufferHeight => 144; + public int BackgroundColor => unchecked((int)0xFF000000); + public int VsyncNumerator => _frameHz; + public int VsyncDenominator => 1; + + public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; + public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; + + public uint[] color_palette = new uint[4]; + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs new file mode 100644 index 0000000000..021a1ac3a0 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IInputPollable + { + public int LagCount + { + get { return _lagcount; } + set { _lagcount = value; } + } + + public bool IsLagFrame + { + get { return _islag; } + set { _islag = value; } + } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + + public bool _islag = true; + private int _lagcount; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs new file mode 100644 index 0000000000..d28fdaba55 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink + { + private IMemoryDomains MemoryDomains; + + public void SetupMemoryDomains() + { + var domains = new List + { + new MemoryDomainDelegate( + "Main RAM L", + L.RAM.Length, + MemoryDomain.Endian.Little, + addr => L.RAM[addr], + (addr, value) => L.RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Main RAM R", + R.RAM.Length, + MemoryDomain.Endian.Little, + addr => R.RAM[addr], + (addr, value) => R.RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Zero Page RAM L", + L.ZP_RAM.Length, + MemoryDomain.Endian.Little, + addr => L.ZP_RAM[addr], + (addr, value) => L.ZP_RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Zero Page RAM R", + R.ZP_RAM.Length, + MemoryDomain.Endian.Little, + addr => R.ZP_RAM[addr], + (addr, value) => R.ZP_RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "System Bus L", + 0X10000, + MemoryDomain.Endian.Little, + addr => PeekSystemBusL(addr), + (addr, value) => PokeSystemBusL(addr, value), + 1), + new MemoryDomainDelegate( + "System Bus R", + 0X10000, + MemoryDomain.Endian.Little, + addr => PeekSystemBusR(addr), + (addr, value) => PokeSystemBusR(addr, value), + 1), + new MemoryDomainDelegate( + "ROM L", + L._rom.Length, + MemoryDomain.Endian.Little, + addr => L._rom[addr], + (addr, value) => L._rom[addr] = value, + 1), + new MemoryDomainDelegate( + "ROM R", + R._rom.Length, + MemoryDomain.Endian.Little, + addr => R._rom[addr], + (addr, value) => R._rom[addr] = value, + 1), + new MemoryDomainDelegate( + "VRAM L", + L.VRAM.Length, + MemoryDomain.Endian.Little, + addr => L.VRAM[addr], + (addr, value) => L.VRAM[addr] = value, + 1), + new MemoryDomainDelegate( + "VRAM R", + R.VRAM.Length, + MemoryDomain.Endian.Little, + addr => R.VRAM[addr], + (addr, value) => R.VRAM[addr] = value, + 1) + }; + + if (L.cart_RAM != null) + { + var CartRamL = new MemoryDomainByteArray("Cart RAM L", MemoryDomain.Endian.Little, L.cart_RAM, true, 1); + domains.Add(CartRamL); + } + + if (R.cart_RAM != null) + { + var CartRamR = new MemoryDomainByteArray("Cart RAM R", MemoryDomain.Endian.Little, R.cart_RAM, true, 1); + domains.Add(CartRamR); + } + + MemoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); + } + + private byte PeekSystemBusL(long addr) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + return L.PeekMemory(addr2); + } + + private byte PeekSystemBusR(long addr) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + return R.PeekMemory(addr2); + } + + private void PokeSystemBusL(long addr, byte value) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + L.WriteMemory(addr2, value); + } + + private void PokeSystemBusR(long addr, byte value) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + R.WriteMemory(addr2, value); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs new file mode 100644 index 0000000000..e8a6a9d0b5 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs @@ -0,0 +1,34 @@ +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : ISaveRam + { + public byte[] CloneSaveRam() + { + if (L.cart_RAM != null) + { + return (byte[])L.cart_RAM.Clone(); + } + else + { + return null; + } + } + + public void StoreSaveRam(byte[] data) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, data.Length); + Console.WriteLine("loading SRAM here"); + } + + public bool SaveRamModified + { + get + { + return L.has_bat & _syncSettings.L.Use_SRAM; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs new file mode 100644 index 0000000000..dd2711ded1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -0,0 +1,91 @@ +using System; +using System.ComponentModel; + +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IEmulator, IStatable, ISettable + { + public GBLinkSettings GetSettings() + { + return new GBLinkSettings + ( + L.GetSettings(), + R.GetSettings() + ); + } + + public GBLinkSyncSettings GetSyncSettings() + { + return new GBLinkSyncSettings + ( + L.GetSyncSettings(), + R.GetSyncSettings() + ); + } + + public bool PutSettings(GBLinkSettings o) + { + return L.PutSettings(o.L) || R.PutSettings(o.R); + } + + public bool PutSyncSettings(GBLinkSyncSettings o) + { + return L.PutSyncSettings(o.L) || R.PutSyncSettings(o.R); + } + + private GBLinkSettings _settings = new GBLinkSettings(); + public GBLinkSyncSettings _syncSettings = new GBLinkSyncSettings(); + + public class GBLinkSettings + { + public GBHawk.GBHawk.GBSettings L; + public GBHawk.GBHawk.GBSettings R; + + public GBLinkSettings() + { + L = new GBHawk.GBHawk.GBSettings(); + R = new GBHawk.GBHawk.GBSettings(); + } + + public GBLinkSettings(GBHawk.GBHawk.GBSettings L, GBHawk.GBHawk.GBSettings R) + { + this.L = L; + this.R = R; + } + + public GBLinkSettings Clone() + { + return new GBLinkSettings(L.Clone(), R.Clone()); + } + } + + public class GBLinkSyncSettings + { + public GBHawk.GBHawk.GBSyncSettings L; + public GBHawk.GBHawk.GBSyncSettings R; + + public GBLinkSyncSettings() + { + L = new GBHawk.GBHawk.GBSyncSettings(); + R = new GBHawk.GBHawk.GBSyncSettings(); + } + + public GBLinkSyncSettings(GBHawk.GBHawk.GBSyncSettings L, GBHawk.GBHawk.GBSyncSettings R) + { + this.L = L; + this.R = R; + } + + public GBLinkSyncSettings Clone() + { + return new GBLinkSyncSettings(L.Clone(), R.Clone()); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs new file mode 100644 index 0000000000..e078e962a9 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -0,0 +1,63 @@ +using System.IO; +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IStatable + { + public bool BinarySaveStatesPreferred => true; + + public void SaveStateText(TextWriter writer) + { + L.SaveStateText(writer); + R.SaveStateText(writer); + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + L.LoadStateText(reader); + R.LoadStateText(reader); + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + L.SaveStateBinary(bw); + R.SaveStateBinary(bw); + // other variables + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + L.LoadStateBinary(br); + R.LoadStateBinary(br); + // other variables + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + //private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; + + private void SyncState(Serializer ser) + { + ser.Sync("Lag", ref _lagcount); + ser.Sync("Frame", ref _frame); + ser.Sync("IsLag", ref _islag); + _controllerDeck.SyncState(ser); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs new file mode 100644 index 0000000000..c4f2ffacda --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -0,0 +1,88 @@ +using System; + +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.LR35902; + +using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + [Core( + "GBHawkLink", + "", + isPorted: false, + isReleased: true)] + [ServiceNotApplicable(typeof(IDriveLight))] + public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable, + ISettable + { + // we want to create two GBHawk instances that we will run concurrently + // maybe up to 4 eventually? + public GBHawk.GBHawk L; + public GBHawk.GBHawk R; + + //[CoreConstructor("GB", "GBC")] + public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings) + { + var ser = new BasicServiceProvider(this); + + GBLinkSettings linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); + GBLinkSyncSettings linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); + _controllerDeck = new GBHawkLinkControllerDeck(GBHawkControllerDeck.DefaultControllerName, GBHawkControllerDeck.DefaultControllerName); + + CoreComm = comm; + + L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game_L, rom_L, linkSettings.L, linkSyncSettings.L); + + R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game_R, rom_R, linkSettings.R, linkSyncSettings.R); + + ser.Register(this); + ser.Register(L.audio); + + _tracer = new TraceBuffer { Header = L.cpu.TraceHeader }; + ser.Register(_tracer); + + ServiceProvider = ser; + + SetupMemoryDomains(); + + HardReset(); + + L.color_palette[0] = color_palette_BW[0]; + L.color_palette[1] = color_palette_BW[1]; + L.color_palette[2] = color_palette_BW[2]; + L.color_palette[3] = color_palette_BW[3]; + + R.color_palette[0] = color_palette_BW[0]; + R.color_palette[1] = color_palette_BW[1]; + R.color_palette[2] = color_palette_BW[2]; + R.color_palette[3] = color_palette_BW[3]; + } + + public void HardReset() + { + L.HardReset(); + R.HardReset(); + } + + public DisplayType Region => DisplayType.NTSC; + + public int _frame = 0; + + private readonly GBHawkLinkControllerDeck _controllerDeck; + + private readonly ITraceable _tracer; + + bool ILinkable.LinkConnected { get; } + + private void ExecFetch(ushort addr) + { + MemoryCallbacks.CallExecutes(addr, "System Bus"); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs new file mode 100644 index 0000000000..fd2e5c7ae8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public class GBHawkLinkControllerDeck + { + public GBHawkLinkControllerDeck(string controller1Name, string controller2Name) + { + if (!ValidControllerTypes.ContainsKey(controller1Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller1Name); + } + + if (!ValidControllerTypes.ContainsKey(controller2Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller2Name); + } + + Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); + Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2); + + Definition = new ControllerDefinition + { + Name = Port1.Definition.Name, + BoolButtons = Port1.Definition.BoolButtons + .Concat(Port2.Definition.BoolButtons) + .ToList() + }; + } + + public byte ReadPort1(IController c) + { + return Port1.Read(c); + } + + public byte ReadPort2(IController c) + { + return Port2.Read(c); + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + ser.BeginSection("Port1"); + Port1.SyncState(ser); + ser.EndSection(); + + ser.BeginSection("Port2"); + Port2.SyncState(ser); + ser.EndSection(); + } + + private readonly IPort Port1; + private readonly IPort Port2; + + private static Dictionary _controllerTypes; + + public static Dictionary ValidControllerTypes + { + get + { + if (_controllerTypes == null) + { + _controllerTypes = typeof(GBHawkLinkControllerDeck).Assembly + .GetTypes() + .Where(t => typeof(IPort).IsAssignableFrom(t)) + .Where(t => !t.IsAbstract && !t.IsInterface) + .ToDictionary(tkey => tkey.DisplayName()); + } + + return _controllerTypes; + } + } + + public static string DefaultControllerName => typeof(StandardControls).DisplayName(); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs new file mode 100644 index 0000000000..b1617ce740 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + /// + /// Represents a GB add on + /// + public interface IPort + { + byte Read(IController c); + + ControllerDefinition Definition { get; } + + void SyncState(Serializer ser); + + int PortNum { get; } + } + + [DisplayName("Gameboy Controller")] + public class StandardControls : IPort + { + public StandardControls(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition + { + Name = "Gameboy Controller H", + BoolButtons = BaseDefinition + .Select(b => "P" + PortNum + " " + b) + .ToList() + }; + } + + public int PortNum { get; } + + public ControllerDefinition Definition { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed(Definition.BoolButtons[0])) + { + result -= 4; + } + if (c.IsPressed(Definition.BoolButtons[1])) + { + result -= 8; + } + if (c.IsPressed(Definition.BoolButtons[2])) + { + result -= 2; + } + if (c.IsPressed(Definition.BoolButtons[3])) + { + result -= 1; + } + if (c.IsPressed(Definition.BoolButtons[4])) + { + result -= 128; + } + if (c.IsPressed(Definition.BoolButtons[5])) + { + result -= 64; + } + if (c.IsPressed(Definition.BoolButtons[6])) + { + result -= 32; + } + if (c.IsPressed(Definition.BoolButtons[7])) + { + result -= 16; + } + + return result; + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" + }; + + public void SyncState(Serializer ser) + { + //nothing + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt new file mode 100644 index 0000000000..bc60bf4b01 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt @@ -0,0 +1 @@ +TODO: From 42764f0019990c93d3eb61719c97f03ecfb68a71 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 4 Jan 2019 08:50:55 +1000 Subject: [PATCH 023/440] Add preliminary Unix compatibility (using Mono; resolves #1384) (#1380) * Move PlatformSpecificLinkedLibs and implementations to common and rename * Specify file ext. at LoadPlatformSpecific call site * Move Client.Common.Global.RunningOnUnix to PlatformLinkedLibSingleton * Inline var Resolver * Use PlatformLinkedLibManager internally * Move plugin load check to LinkedLibManager, use LinkedLibManager * Interpolate * Return exit code from dlclose/FreeLibrary * Skip all calls to externs in BlipBufDll when using mono * Use PlatformLinkedLibManager in SevenZipLibraryManager * Add expected return value to workaround (from testing on Win32) * Remove ".dll" from DllImport attr, remove temporary workaround, see desc. The library can be built by changing the output file name in `.../blip_buf/Makefile` to `libblip_buf.so`, and running `make`. It will be loaded if placed in the `.../output` folder. * Remove unused code, add TODO (this class is req. for Waterbox.PeWrapper) The TODO is to [rewrite with C#](https://docs.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files) instead of importing from `kernel32.dll`. * Update OpenTK again but better (for #1384) * Add Mono run script * Add libblip_buf.so (temporary) Temporary because it should be a separate package which BizHawk depends on. * Add distro detection, add "already running" and "unknown distro" messages * Gray-out Lua Console on Unix * Extract superclass from EmuLuaLibrary, add shell implementation for Unix * Specify libdl version, Fedora doesn't have the versionless symlink * Remove empty `ToolStripMenuItem`, null `Text` caused crash on Unix * Transform OpenTK keyboard input into a `List` and read that Also fixes crash on rebind * Remove debug `using ...;` --- Assets/EmuHawkMono.sh | 18 ++++ Assets/libblip_buf.so | Bin 0 -> 16840 bytes BizHawk.Client.Common/7z/LibraryManager.cs | 18 ++-- BizHawk.Client.Common/7z/NativeMethods.cs | 12 +-- BizHawk.Client.Common/Global.cs | 2 - .../BizHawk.Client.EmuHawk.csproj | 2 + BizHawk.Client.EmuHawk/Input/Input.cs | 37 +++---- BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs | 38 +++++++- BizHawk.Client.EmuHawk/MainForm.Events.cs | 1 + BizHawk.Client.EmuHawk/MainForm.cs | 4 - BizHawk.Client.EmuHawk/Program.cs | 80 +++------------ BizHawk.Client.EmuHawk/ScreenSaver.cs | 3 +- BizHawk.Client.EmuHawk/Sound/Sound.cs | 3 +- BizHawk.Client.EmuHawk/Throttle.cs | 3 +- BizHawk.Client.EmuHawk/config/InputWidget.cs | 6 +- .../tools/Lua/Libraries/EmuLuaLibrary.cs | 56 ++++++----- .../Lua/Libraries/NotReallyLuaLibrary.cs | 60 ++++++++++++ .../Lua/Libraries/PlatformEmuLuaLibrary.cs | 45 +++++++++ .../tools/Lua/LuaConsole.cs | 47 ++++----- .../tools/Lua/LuaRegisteredFunctionsList.cs | 14 +-- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 8 +- .../tools/TraceLogger.Designer.cs | 8 -- BizHawk.Common/BizHawk.Common.csproj | 1 + .../BizInvoke/DynamicLibraryImportResolver.cs | 56 ++--------- BizHawk.Common/BizInvoke/MemoryBlock.cs | 29 +----- BizHawk.Common/PlatformLinkedLibSingleton.cs | 86 +++++++++++++++++ .../Sound/Utilities/BlipBuffer.cs | 24 ++--- .../N64/NativeApi/mupen64plusCoreApi.cs | 91 ++++++++---------- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 4 +- References/OpenTK.GLControl.dll | Bin 28672 -> 45056 bytes References/OpenTK.dll | Bin 5525504 -> 5525504 bytes References/OpenTK.dll.config | 41 +++++--- 32 files changed, 455 insertions(+), 342 deletions(-) create mode 100755 Assets/EmuHawkMono.sh create mode 100755 Assets/libblip_buf.so create mode 100644 BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs create mode 100644 BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs create mode 100644 BizHawk.Common/PlatformLinkedLibSingleton.cs diff --git a/Assets/EmuHawkMono.sh b/Assets/EmuHawkMono.sh new file mode 100755 index 0000000000..45298de879 --- /dev/null +++ b/Assets/EmuHawkMono.sh @@ -0,0 +1,18 @@ +#!/bin/sh +cd "$(dirname "$0")" +if [ "$(ps -C "mono" -o "cmd" --no-headers | grep "EmuHawk.exe")" ]; then + echo "EmuHawk is already running, exiting..." + exit 0 +fi +libpath="" +if [ "$(command -v lsb_release)" ]; then + case "$(lsb_release -i | cut -c17- | tr -d "\n")" in + "Arch"|"ManjaroLinux") libpath="/usr/lib/wine";; + "Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";; + esac +fi +if [ -z "$libpath" ]; then + printf "%s\n" "Unknown distro, assuming WINE library location is /usr/lib/wine..." + libpath="/usr/lib/wine" +fi +LD_LIBRARY_PATH="$libpath" mono ./EmuHawk.exe diff --git a/Assets/libblip_buf.so b/Assets/libblip_buf.so new file mode 100755 index 0000000000000000000000000000000000000000..9c060d4189a81d6404d0cfaa8cddccffd5375194 GIT binary patch literal 16840 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 y?D@g(Thrm. */ +using BizHawk.Common; + using System; using System.Collections.Generic; #if !WINCE && !MONO @@ -87,6 +89,8 @@ namespace SevenZip // private static string _LibraryVersion; private static bool? _modifyCapabale; + private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; + private static void InitUserInFormat(object user, InArchiveFormat format) { if (!_inArchives.ContainsKey(user)) @@ -148,16 +152,16 @@ namespace SevenZip //{ // throw new SevenZipLibraryException("DLL file does not exist."); //} - if ((_modulePtr = NativeMethods.LoadLibrary(_libraryFileName)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadPlatformSpecific(_libraryFileName)) == IntPtr.Zero) { //try a different directory string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll"); - if ((_modulePtr = NativeMethods.LoadLibrary(alternateFilename)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadPlatformSpecific(alternateFilename)) == IntPtr.Zero) throw new SevenZipLibraryException("failed to load library."); } - if (NativeMethods.GetProcAddress(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) + if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) { - NativeMethods.FreeLibrary(_modulePtr); + libLoader.FreePlatformSpecific(_modulePtr); throw new SevenZipLibraryException("library is invalid."); } } @@ -431,7 +435,7 @@ namespace SevenZip if (_totalUsers == 0) { #if !WINCE && !MONO - NativeMethods.FreeLibrary(_modulePtr); + libLoader.FreePlatformSpecific(_modulePtr); #endif _modulePtr = IntPtr.Zero; @@ -466,7 +470,7 @@ namespace SevenZip } var createObject = (NativeMethods.CreateObjectDelegate) Marshal.GetDelegateForFunctionPointer( - NativeMethods.GetProcAddress(_modulePtr, "CreateObject"), + libLoader.GetProcAddr(_modulePtr, "CreateObject"), typeof(NativeMethods.CreateObjectDelegate)); if (createObject == null) { @@ -525,7 +529,7 @@ namespace SevenZip } var createObject = (NativeMethods.CreateObjectDelegate) Marshal.GetDelegateForFunctionPointer( - NativeMethods.GetProcAddress(_modulePtr, "CreateObject"), + libLoader.GetProcAddr(_modulePtr, "CreateObject"), typeof(NativeMethods.CreateObjectDelegate)); if (createObject == null) { diff --git a/BizHawk.Client.Common/7z/NativeMethods.cs b/BizHawk.Client.Common/7z/NativeMethods.cs index 02ef5e7eb4..33fbcd9998 100644 --- a/BizHawk.Client.Common/7z/NativeMethods.cs +++ b/BizHawk.Client.Common/7z/NativeMethods.cs @@ -35,18 +35,8 @@ namespace SevenZip [MarshalAs(UnmanagedType.Interface)] out object outObject); #endregion - - [DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] - public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName); - - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool FreeLibrary(IntPtr hModule); - - [DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] - public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); #endif - + #if WINCE [DllImport("7z.dll", EntryPoint="CreateObject")] public static extern int CreateCOMObject( diff --git a/BizHawk.Client.Common/Global.cs b/BizHawk.Client.Common/Global.cs index 3631df9a7b..c233e7a7ec 100644 --- a/BizHawk.Client.Common/Global.cs +++ b/BizHawk.Client.Common/Global.cs @@ -159,7 +159,5 @@ namespace BizHawk.Client.Common } public static Dictionary UserBag = new Dictionary(); - - public static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; } } diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 646beb4e11..2587f62945 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -943,6 +943,8 @@ + + Form diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index a812d55017..0727baeffe 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -2,11 +2,8 @@ using System.Linq; using System.Collections.Generic; using System.Threading; -#if WINDOWS + using SlimDX.DirectInput; -#else -using OpenTK.Input; -#endif using BizHawk.Common; using BizHawk.Client.Common; @@ -116,19 +113,17 @@ namespace BizHawk.Client.EmuHawk private Input() { -#if WINDOWS UpdateThread = new Thread(UpdateThreadProc) { IsBackground = true, Priority = ThreadPriority.AboveNormal //why not? this thread shouldn't be very heavy duty, and we want it to be responsive }; UpdateThread.Start(); -#endif } public static void Initialize() { - if (Global.RunningOnUnix) + if (PlatformLinkedLibSingleton.RunningOnUnix) { OTK_Keyboard.Initialize(); // OTK_Gamepad.Initialize(); @@ -145,10 +140,11 @@ namespace BizHawk.Client.EmuHawk public static void Cleanup() { -#if WINDOWS - KeyInput.Cleanup(); - GamePad.Cleanup(); -#endif + if (!PlatformLinkedLibSingleton.RunningOnUnix) + { + KeyInput.Cleanup(); + GamePad.Cleanup(); + } } public enum InputEventType @@ -331,14 +327,22 @@ namespace BizHawk.Client.EmuHawk return FloatValuesCopy; } -#if WINDOWS void UpdateThreadProc() { - for (; ; ) + while (true) { - var keyEvents = KeyInput.Update().Concat(IPCKeyInput.Update()); - GamePad.UpdateAll(); - GamePad360.UpdateAll(); + var keyEvents = PlatformLinkedLibSingleton.RunningOnUnix + ? OTK_Keyboard.Update() + : KeyInput.Update().Concat(IPCKeyInput.Update()); + if (PlatformLinkedLibSingleton.RunningOnUnix) + { + //TODO + } + else + { + GamePad.UpdateAll(); + GamePad360.UpdateAll(); + } //this block is going to massively modify data structures that the binding method uses, so we have to lock it all lock (this) @@ -441,7 +445,6 @@ namespace BizHawk.Client.EmuHawk Thread.Sleep(10); } } -#endif public void StartListeningForFloatEvents() { diff --git a/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs b/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs index 2c8faa7cbb..200c970e6b 100644 --- a/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs +++ b/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs @@ -6,18 +6,47 @@ namespace BizHawk.Client.EmuHawk { public static class OTK_Keyboard { - private static OpenTK.Input.KeyboardState _kbState; + private static readonly Dictionary KeyEnumMap = new Dictionary + { + // A-Z + {Key.A, SlimDX.DirectInput.Key.A}, {Key.B, SlimDX.DirectInput.Key.B}, {Key.C, SlimDX.DirectInput.Key.C}, {Key.D, SlimDX.DirectInput.Key.D}, {Key.E, SlimDX.DirectInput.Key.E}, {Key.F, SlimDX.DirectInput.Key.F}, {Key.G, SlimDX.DirectInput.Key.G}, {Key.H, SlimDX.DirectInput.Key.H}, {Key.I, SlimDX.DirectInput.Key.I}, {Key.J, SlimDX.DirectInput.Key.J}, {Key.K, SlimDX.DirectInput.Key.K}, {Key.L, SlimDX.DirectInput.Key.L}, {Key.M, SlimDX.DirectInput.Key.M}, {Key.N, SlimDX.DirectInput.Key.N}, {Key.O, SlimDX.DirectInput.Key.O}, {Key.P, SlimDX.DirectInput.Key.P}, {Key.Q, SlimDX.DirectInput.Key.Q}, {Key.R, SlimDX.DirectInput.Key.R}, {Key.S, SlimDX.DirectInput.Key.S}, {Key.T, SlimDX.DirectInput.Key.T}, {Key.U, SlimDX.DirectInput.Key.U}, {Key.V, SlimDX.DirectInput.Key.V}, {Key.W, SlimDX.DirectInput.Key.W}, {Key.X, SlimDX.DirectInput.Key.X}, {Key.Y, SlimDX.DirectInput.Key.Y}, {Key.Z, SlimDX.DirectInput.Key.Z}, + // 0-9 + {Key.Number1, SlimDX.DirectInput.Key.D1}, {Key.Number2, SlimDX.DirectInput.Key.D2}, {Key.Number3, SlimDX.DirectInput.Key.D3}, {Key.Number4, SlimDX.DirectInput.Key.D4}, {Key.Number5, SlimDX.DirectInput.Key.D5}, {Key.Number6, SlimDX.DirectInput.Key.D6}, {Key.Number7, SlimDX.DirectInput.Key.D7}, {Key.Number8, SlimDX.DirectInput.Key.D8}, {Key.Number9, SlimDX.DirectInput.Key.D9}, {Key.Number0, SlimDX.DirectInput.Key.D0}, + // misc. printables (ASCII order) + {Key.Space, SlimDX.DirectInput.Key.Space}, {Key.Quote, SlimDX.DirectInput.Key.Apostrophe}, {Key.Comma, SlimDX.DirectInput.Key.Comma}, {Key.Minus, SlimDX.DirectInput.Key.Minus}, {Key.Period, SlimDX.DirectInput.Key.Period}, {Key.Slash, SlimDX.DirectInput.Key.Slash}, {Key.Semicolon, SlimDX.DirectInput.Key.Semicolon}, {Key.Plus, SlimDX.DirectInput.Key.Equals}, {Key.BracketLeft, SlimDX.DirectInput.Key.LeftBracket}, {Key.BackSlash, SlimDX.DirectInput.Key.Backslash}, {Key.BracketRight, SlimDX.DirectInput.Key.RightBracket}, {Key.Tilde, SlimDX.DirectInput.Key.Grave}, + // misc. (alphabetically) + {Key.BackSpace, SlimDX.DirectInput.Key.Backspace}, {Key.CapsLock, SlimDX.DirectInput.Key.CapsLock}, {Key.Delete, SlimDX.DirectInput.Key.Delete}, {Key.Down, SlimDX.DirectInput.Key.DownArrow}, {Key.End, SlimDX.DirectInput.Key.End}, {Key.Enter, SlimDX.DirectInput.Key.Return}, {Key.Escape, SlimDX.DirectInput.Key.Escape}, {Key.Home, SlimDX.DirectInput.Key.Home}, {Key.Insert, SlimDX.DirectInput.Key.Insert}, {Key.Left, SlimDX.DirectInput.Key.LeftArrow}, {Key.PageDown, SlimDX.DirectInput.Key.PageDown}, {Key.PageUp, SlimDX.DirectInput.Key.PageUp}, {Key.Pause, SlimDX.DirectInput.Key.Pause}, {Key.Right, SlimDX.DirectInput.Key.RightArrow}, {Key.ScrollLock, SlimDX.DirectInput.Key.ScrollLock}, {Key.Tab, SlimDX.DirectInput.Key.Tab}, {Key.Up, SlimDX.DirectInput.Key.UpArrow}, + // modifier + {Key.WinLeft, SlimDX.DirectInput.Key.LeftWindowsKey}, {Key.WinRight, SlimDX.DirectInput.Key.RightWindowsKey}, {Key.ControlLeft, SlimDX.DirectInput.Key.LeftControl}, {Key.ControlRight, SlimDX.DirectInput.Key.RightControl}, {Key.AltLeft, SlimDX.DirectInput.Key.LeftAlt}, {Key.AltRight, SlimDX.DirectInput.Key.RightAlt}, {Key.ShiftLeft, SlimDX.DirectInput.Key.LeftShift}, {Key.ShiftRight, SlimDX.DirectInput.Key.RightShift}, + + // function + {Key.F1, SlimDX.DirectInput.Key.F1}, {Key.F2, SlimDX.DirectInput.Key.F2}, {Key.F3, SlimDX.DirectInput.Key.F3}, {Key.F4, SlimDX.DirectInput.Key.F4}, {Key.F5, SlimDX.DirectInput.Key.F5}, {Key.F6, SlimDX.DirectInput.Key.F6}, {Key.F7, SlimDX.DirectInput.Key.F7}, {Key.F8, SlimDX.DirectInput.Key.F8}, {Key.F9, SlimDX.DirectInput.Key.F9}, {Key.F10, SlimDX.DirectInput.Key.F10}, {Key.F11, SlimDX.DirectInput.Key.F11}, {Key.F12, SlimDX.DirectInput.Key.F12}, + // keypad (alphabetically) + {Key.Keypad0, SlimDX.DirectInput.Key.NumberPad0}, {Key.Keypad1, SlimDX.DirectInput.Key.NumberPad1}, {Key.Keypad2, SlimDX.DirectInput.Key.NumberPad2}, {Key.Keypad3, SlimDX.DirectInput.Key.NumberPad3}, {Key.Keypad4, SlimDX.DirectInput.Key.NumberPad4}, {Key.Keypad5, SlimDX.DirectInput.Key.NumberPad5}, {Key.Keypad6, SlimDX.DirectInput.Key.NumberPad6}, {Key.Keypad7, SlimDX.DirectInput.Key.NumberPad7}, {Key.Keypad8, SlimDX.DirectInput.Key.NumberPad8}, {Key.Keypad9, SlimDX.DirectInput.Key.NumberPad9}, {Key.KeypadAdd, SlimDX.DirectInput.Key.NumberPadPlus}, {Key.KeypadDecimal, SlimDX.DirectInput.Key.NumberPadPeriod}, {Key.KeypadDivide, SlimDX.DirectInput.Key.NumberPadSlash}, {Key.KeypadEnter, SlimDX.DirectInput.Key.NumberPadEnter}, {Key.KeypadMultiply, SlimDX.DirectInput.Key.NumberPadStar}, {Key.KeypadSubtract, SlimDX.DirectInput.Key.NumberPadMinus} + }; + + private static readonly List _eventList = new List(); + private static KeyboardState _kbState; public static void Initialize () { - _kbState = OpenTK.Input.Keyboard.GetState(); + _kbState = Keyboard.GetState(); } - public static void Update () + public static IEnumerable Update () { + _eventList.Clear(); + var lastState = _kbState; try { - _kbState = OpenTK.Input.Keyboard.GetState(); + _kbState = Keyboard.GetState(); + foreach (KeyValuePair entry in KeyEnumMap) + { + if (lastState.IsKeyUp(entry.Key) && _kbState.IsKeyDown(entry.Key)) + _eventList.Add(new KeyInput.KeyEvent { Key = entry.Value, Pressed = true }); + else if (lastState.IsKeyDown(entry.Key) && _kbState.IsKeyUp(entry.Key)) + _eventList.Add(new KeyInput.KeyEvent { Key = entry.Value, Pressed = false }); + } } catch { @@ -30,6 +59,7 @@ namespace BizHawk.Client.EmuHawk System.Console.WriteLine("OpenTK Keyboard thread is angry."); } } + return _eventList; } public static bool IsPressed (Key key) diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index e47ce7a138..583898ae0f 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1386,6 +1386,7 @@ namespace BizHawk.Client.EmuHawk RamSearchMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["RAM Search"].Bindings; HexEditorMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Hex Editor"].Bindings; LuaConsoleMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Lua Console"].Bindings; + LuaConsoleMenuItem.Enabled = GlobalWin.Tools.IsAvailable(); CheatsMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Cheats"].Bindings; TAStudioMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["TAStudio"].Bindings; VirtualPadMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Virtual Pad"].Bindings; diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 5eb4a1d93d..9684d7b21e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -1118,11 +1118,7 @@ namespace BizHawk.Client.EmuHawk private void OpenLuaConsole() { -#if WINDOWS GlobalWin.Tools.Load(); -#else - MessageBox.Show("Sorry, Lua is not supported on this platform.", "Lua not supported", MessageBoxButtons.OK, MessageBoxIcon.Error); -#endif } public void NotifyLogWindowClosing() diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index 8321603006..cc970daf55 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -17,26 +17,25 @@ namespace BizHawk.Client.EmuHawk { static class Program { - static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; - static Program() { //this needs to be done before the warnings/errors show up Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - PlatformSpecificLinkedLibs libLoader = RunningOnUnix ? (PlatformSpecificLinkedLibs) new UnixMono() : (PlatformSpecificLinkedLibs) new Win32(); + var libLoader = PlatformLinkedLibSingleton.LinkedLibManager; //http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips //try loading libraries we know we'll need //something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing //but oddly it lets us proceed and we'll then catch it here - var d3dx9 = libLoader.LoadPlatformSpecific("d3dx9_43.dll"); - var vc2015 = libLoader.LoadPlatformSpecific("vcruntime140.dll"); - var vc2012 = libLoader.LoadPlatformSpecific("msvcr120.dll"); //TODO - check version? - var vc2010 = libLoader.LoadPlatformSpecific("msvcr100.dll"); //TODO - check version? - var vc2010p = libLoader.LoadPlatformSpecific("msvcp100.dll"); + var libExt = PlatformLinkedLibSingleton.RunningOnUnix ? ".dll.so" : ".dll"; + var d3dx9 = libLoader.LoadPlatformSpecific($"d3dx9_43{libExt}"); + var vc2015 = libLoader.LoadPlatformSpecific($"vcruntime140{libExt}"); + var vc2012 = libLoader.LoadPlatformSpecific($"msvcr120{libExt}"); //TODO - check version? + var vc2010 = libLoader.LoadPlatformSpecific($"msvcr100{libExt}"); //TODO - check version? + var vc2010p = libLoader.LoadPlatformSpecific($"msvcp100{libExt}"); bool fail = false, warn = false; warn |= d3dx9 == IntPtr.Zero; fail |= vc2015 == IntPtr.Zero; @@ -66,7 +65,7 @@ namespace BizHawk.Client.EmuHawk libLoader.FreePlatformSpecific(vc2010); libLoader.FreePlatformSpecific(vc2010p); - if (!RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { // this will look in subdirectory "dll" to load pinvoked stuff string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); @@ -90,63 +89,6 @@ namespace BizHawk.Client.EmuHawk return SubMain(args); } - private interface PlatformSpecificLinkedLibs - { - IntPtr LoadPlatformSpecific(string dllToLoad); - IntPtr GetProcAddr(IntPtr hModule, string procName); - void FreePlatformSpecific(IntPtr hModule); - } - private class Win32 : PlatformSpecificLinkedLibs - { - [DllImport("kernel32.dll")] - private static extern IntPtr LoadLibrary(string dllToLoad); - [DllImport("kernel32.dll")] - private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - [DllImport("kernel32.dll")] - private static extern void FreeLibrary(IntPtr hModule); - public IntPtr LoadPlatformSpecific(string dllToLoad) - { - return LoadLibrary(dllToLoad); - } - public IntPtr GetProcAddr(IntPtr hModule, string procName) - { - return GetProcAddress(hModule, procName); - } - public void FreePlatformSpecific(IntPtr hModule) - { - FreeLibrary(hModule); - } - } - private class UnixMono : PlatformSpecificLinkedLibs - { - // This class is copied from a tutorial, so don't git blame and then email me expecting insight. - const int RTLD_NOW = 2; - [DllImport("libdl.so")] - private static extern IntPtr dlopen(String fileName, int flags); - [DllImport("libdl.so")] - private static extern IntPtr dlerror(); - [DllImport("libdl.so")] - private static extern IntPtr dlsym(IntPtr handle, String symbol); - [DllImport("libdl.so")] - private static extern int dlclose(IntPtr handle); - public IntPtr LoadPlatformSpecific(string dllToLoad) - { - return dlopen(dllToLoad + ".so", RTLD_NOW); - } - public IntPtr GetProcAddr(IntPtr hModule, string procName) - { - dlerror(); - var res = dlsym(hModule, procName); - var errPtr = dlerror(); - if (errPtr != IntPtr.Zero) throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr)); - return res; - } - public void FreePlatformSpecific(IntPtr hModule) - { - dlclose(hModule); - } - } - private interface PlatformSpecificMainLoopCrashHandler { void TryCatchFinally(string[] args); @@ -258,7 +200,7 @@ namespace BizHawk.Client.EmuHawk } } } - private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = RunningOnUnix + private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificMainLoopCrashHandler) new UnixMonoMainLoopCrashHandler() : (PlatformSpecificMainLoopCrashHandler) new Win32MainLoopCrashHandler(); @@ -323,7 +265,7 @@ namespace BizHawk.Client.EmuHawk GlobalWin.GLManager = GLManager.Instance; //now create the "GL" context for the display method. we can reuse the IGL_TK context if opengl display method is chosen - if (RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; + if (PlatformLinkedLibSingleton.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; REDO_DISPMETHOD: if (Global.Config.DispMethod == Config.EDispMethod.GdiPlus) GlobalWin.GL = new Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus(); @@ -371,7 +313,7 @@ namespace BizHawk.Client.EmuHawk goto REDO_DISPMETHOD; } - if (!RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { //WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff. //The relevant initialization happened just before in "create IGL context". diff --git a/BizHawk.Client.EmuHawk/ScreenSaver.cs b/BizHawk.Client.EmuHawk/ScreenSaver.cs index 70aedf1540..d362b4b2c2 100644 --- a/BizHawk.Client.EmuHawk/ScreenSaver.cs +++ b/BizHawk.Client.EmuHawk/ScreenSaver.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using BizHawk.Client.Common; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -40,7 +41,7 @@ namespace BizHawk.Client.EmuHawk //TODO implement } } - private static PlatformSpecificScreenBlankInterface screenBlankInterface = Global.RunningOnUnix + private static PlatformSpecificScreenBlankInterface screenBlankInterface = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificScreenBlankInterface) new MiscUnixScreenBlankInterface() : (PlatformSpecificScreenBlankInterface) new WinScreenBlankInterface(); diff --git a/BizHawk.Client.EmuHawk/Sound/Sound.cs b/BizHawk.Client.EmuHawk/Sound/Sound.cs index 93abdb7f40..1edaaae699 100644 --- a/BizHawk.Client.EmuHawk/Sound/Sound.cs +++ b/BizHawk.Client.EmuHawk/Sound/Sound.cs @@ -4,6 +4,7 @@ using System.Threading; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Client.Common; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -26,7 +27,7 @@ namespace BizHawk.Client.EmuHawk { if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL) _outputDevice = new OpenALSoundOutput(this); - if (!Global.RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound) _outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle); diff --git a/BizHawk.Client.EmuHawk/Throttle.cs b/BizHawk.Client.EmuHawk/Throttle.cs index 3ae65cdc70..5eb8fcba22 100644 --- a/BizHawk.Client.EmuHawk/Throttle.cs +++ b/BizHawk.Client.EmuHawk/Throttle.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Threading; using BizHawk.Client.Common; +using BizHawk.Common; //this throttle is nitsuja's fine-tuned techniques from desmume @@ -159,7 +160,7 @@ namespace BizHawk.Client.EmuHawk return timeBeginPeriod(ms); } } - static PlatformSpecificSysTimer sysTimer = Global.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer(); + static PlatformSpecificSysTimer sysTimer = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer(); static uint TimeBeginPeriod(uint ms) { return sysTimer.TimeBeginPeriod(ms); diff --git a/BizHawk.Client.EmuHawk/config/InputWidget.cs b/BizHawk.Client.EmuHawk/config/InputWidget.cs index f02130560c..79167ea11f 100644 --- a/BizHawk.Client.EmuHawk/config/InputWidget.cs +++ b/BizHawk.Client.EmuHawk/config/InputWidget.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; +using BizHawk.Common; + namespace BizHawk.Client.EmuHawk { public sealed class InputWidget : TextBox @@ -69,7 +71,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnMouseClick(MouseEventArgs e) { - HideCaret(Handle); + if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle); base.OnMouseClick(e); } @@ -262,7 +264,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnGotFocus(EventArgs e) { - HideCaret(Handle); + if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs index 30b1c40f7c..08efa298d3 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs @@ -13,7 +13,7 @@ using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public class EmuLuaLibrary + public class EmuLuaLibrary : PlatformEmuLuaLibrary { public EmuLuaLibrary() { @@ -82,16 +82,6 @@ namespace BizHawk.Client.EmuHawk } } - public bool IsRebootingCore { get; set; } // pretty hacky.. we dont want a lua script to be able to restart itself by rebooting the core - - private readonly Dictionary Libraries = new Dictionary(); - public LuaFileList ScriptList { get; } = new LuaFileList(); - - public IEnumerable RunningScripts - { - get { return ScriptList.Where(lf => lf.Enabled); } - } - private Lua _lua = new Lua(); private Lua _currThread; @@ -101,9 +91,7 @@ namespace BizHawk.Client.EmuHawk private EmulatorLuaLibrary EmulatorLuaLibrary => (EmulatorLuaLibrary)Libraries[typeof(EmulatorLuaLibrary)]; - public GuiLuaLibrary GuiLibrary => (GuiLuaLibrary)Libraries[typeof(GuiLuaLibrary)]; - - public void Restart(IEmulatorServiceProvider newServiceProvider) + public override void Restart(IEmulatorServiceProvider newServiceProvider) { foreach (var lib in Libraries) { @@ -111,7 +99,7 @@ namespace BizHawk.Client.EmuHawk } } - public void StartLuaDrawing() + public override void StartLuaDrawing() { if (ScriptList.Any() && GuiLibrary.SurfaceIsNull) { @@ -119,7 +107,7 @@ namespace BizHawk.Client.EmuHawk } } - public void EndLuaDrawing() + public override void EndLuaDrawing() { if (ScriptList.Any()) { @@ -127,34 +115,35 @@ namespace BizHawk.Client.EmuHawk } } - public LuaDocumentation Docs { get; } public bool IsRunning { get; set; } - public EventWaitHandle LuaWait { get; private set; } public bool FrameAdvanceRequested { get; private set; } - public LuaFunctionList RegisteredFunctions => EventsLibrary.RegisteredFunctions; + public override LuaFunctionList GetRegisteredFunctions() + { + return EventsLibrary.RegisteredFunctions; + } - public void WindowClosed(IntPtr handle) + public override void WindowClosed(IntPtr handle) { FormsLibrary.WindowClosed(handle); } - public void CallSaveStateEvent(string name) + public override void CallSaveStateEvent(string name) { EventsLibrary.CallSaveStateEvent(name); } - public void CallLoadStateEvent(string name) + public override void CallLoadStateEvent(string name) { EventsLibrary.CallLoadStateEvent(name); } - public void CallFrameBeforeEvent() + public override void CallFrameBeforeEvent() { EventsLibrary.CallFrameBeforeEvent(); } - public void CallFrameAfterEvent() + public override void CallFrameAfterEvent() { EventsLibrary.CallFrameAfterEvent(); } @@ -164,7 +153,12 @@ namespace BizHawk.Client.EmuHawk EventsLibrary.CallExitEvent(thread); } - public void Close() + public override void CallExitEvent(LuaFile lf) + { + CallExitEvent(lf.Thread); + } + + public override void Close() { FormsLibrary.DestroyAll(); _lua.Close(); @@ -187,7 +181,12 @@ namespace BizHawk.Client.EmuHawk return lua; } - public void ExecuteString(string command) + public override void SpawnAndSetFileThread(string pathToLoad, LuaFile lf) + { + lf.Thread = SpawnCoroutine(pathToLoad); + } + + public override void ExecuteString(string command) { _currThread = _lua.NewThread(); _currThread.DoString(command); @@ -232,6 +231,11 @@ namespace BizHawk.Client.EmuHawk } } + public override ResumeResult ResumeScriptFromThreadOf(LuaFile lf) + { + return ResumeScript(lf.Thread); + } + public static void Print(params object[] outputs) { ConsoleLuaLibrary.Log(outputs); diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs new file mode 100644 index 0000000000..e47b7e750b --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs @@ -0,0 +1,60 @@ +using System; + +using BizHawk.Client.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// Methods intentionally blank. + /// + public sealed class NotReallyLuaLibrary : PlatformEmuLuaLibrary + { + public override void CallExitEvent(LuaFile lf) + { + } + public override void CallFrameAfterEvent() + { + } + public override void CallFrameBeforeEvent() + { + } + public override void CallLoadStateEvent(string name) + { + } + public override void CallSaveStateEvent(string name) + { + } + public override void Close() + { + } + public override void EndLuaDrawing() + { + } + public override void ExecuteString(string command) + { + } + private static readonly LuaFunctionList EmptyLuaFunList = new LuaFunctionList(); + public override LuaFunctionList GetRegisteredFunctions() + { + return EmptyLuaFunList; + } + public override void Restart(IEmulatorServiceProvider newServiceProvider) + { + } + private static readonly EmuLuaLibrary.ResumeResult EmptyResumeResult = new EmuLuaLibrary.ResumeResult(); + public override EmuLuaLibrary.ResumeResult ResumeScriptFromThreadOf(LuaFile lf) + { + return EmptyResumeResult; + } + public override void SpawnAndSetFileThread(string pathToLoad, LuaFile lf) + { + } + public override void StartLuaDrawing() + { + } + public override void WindowClosed(IntPtr handle) + { + } + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs new file mode 100644 index 0000000000..93c99a0427 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using BizHawk.Client.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public abstract class PlatformEmuLuaLibrary + { + public LuaDocumentation Docs { get; protected set; } + + public GuiLuaLibrary GuiLibrary => (GuiLuaLibrary) Libraries[typeof(GuiLuaLibrary)]; + + public bool IsRebootingCore { get; set; } // pretty hacky.. we dont want a lua script to be able to restart itself by rebooting the core + + protected readonly Dictionary Libraries = new Dictionary(); + + public EventWaitHandle LuaWait { get; protected set; } + + public IEnumerable RunningScripts + { + get { return ScriptList.Where(lf => lf.Enabled); } + } + + public readonly LuaFileList ScriptList = new LuaFileList(); + + public abstract void CallExitEvent(LuaFile lf); + public abstract void CallFrameAfterEvent(); + public abstract void CallFrameBeforeEvent(); + public abstract void CallLoadStateEvent(string name); + public abstract void CallSaveStateEvent(string name); + public abstract void Close(); + public abstract void EndLuaDrawing(); + public abstract void ExecuteString(string command); + public abstract LuaFunctionList GetRegisteredFunctions(); + public abstract void Restart(IEmulatorServiceProvider newServiceProvider); + public abstract EmuLuaLibrary.ResumeResult ResumeScriptFromThreadOf(LuaFile lf); + public abstract void SpawnAndSetFileThread(string pathToLoad, LuaFile lf); + public abstract void StartLuaDrawing(); + public abstract void WindowClosed(IntPtr handle); + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 881e32d219..c84ad96923 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -7,10 +7,11 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; -using BizHawk.Emulation.Common; using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; +using BizHawk.Client.EmuHawk.WinFormExtensions; +using BizHawk.Common; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -78,7 +79,7 @@ namespace BizHawk.Client.EmuHawk LuaSandbox.DefaultLogger = ConsoleLog; } - public EmuLuaLibrary LuaImp { get; private set; } + public PlatformEmuLuaLibrary LuaImp { get; private set; } public bool UpdateBefore => true; @@ -154,15 +155,15 @@ namespace BizHawk.Client.EmuHawk foreach (var file in runningScripts) { - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); - var functions = LuaImp.RegisteredFunctions + var functions = LuaImp.GetRegisteredFunctions() .Where(lf => lf.Lua == file.Thread) .ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } UpdateRegisteredFunctionsDialog(); @@ -172,7 +173,9 @@ namespace BizHawk.Client.EmuHawk } var currentScripts = LuaImp?.ScriptList; // Temp fix for now - LuaImp = new EmuLuaLibrary(Emulator.ServiceProvider); + LuaImp = PlatformLinkedLibSingleton.RunningOnUnix + ? (PlatformEmuLuaLibrary) new NotReallyLuaLibrary() + : (PlatformEmuLuaLibrary) new EmuLuaLibrary(Emulator.ServiceProvider); if (currentScripts != null) { LuaImp.ScriptList.AddRange(currentScripts); @@ -188,7 +191,7 @@ namespace BizHawk.Client.EmuHawk { LuaSandbox.Sandbox(file.Thread, () => { - file.Thread = LuaImp.SpawnCoroutine(pathToLoad); + LuaImp.SpawnAndSetFileThread(pathToLoad, file); LuaSandbox.CreateSandbox(file.Thread, Path.GetDirectoryName(pathToLoad)); file.State = LuaFile.RunState.Running; }, () => @@ -306,7 +309,7 @@ namespace BizHawk.Client.EmuHawk LuaSandbox.Sandbox(null, () => { string pathToLoad = ProcessPath(file.Path); - file.Thread = LuaImp.SpawnCoroutine(file.Path); + LuaImp.SpawnAndSetFileThread(file.Path, file); LuaSandbox.CreateSandbox(file.Thread, Path.GetDirectoryName(pathToLoad)); }, () => { @@ -552,10 +555,10 @@ namespace BizHawk.Client.EmuHawk var prohibit = lf.FrameWaiting && !includeFrameWaiters; if (!prohibit) { - var result = LuaImp.ResumeScript(lf.Thread); + var result = LuaImp.ResumeScriptFromThreadOf(lf); if (result.Terminated) { - LuaImp.CallExitEvent(lf.Thread); + LuaImp.CallExitEvent(lf); lf.Stop(); UpdateDialog(); } @@ -786,7 +789,7 @@ namespace BizHawk.Client.EmuHawk SelectAllMenuItem.Enabled = LuaImp.ScriptList.Any(); StopAllScriptsMenuItem.Enabled = LuaImp.ScriptList.Any(script => script.Enabled); - RegisteredFunctionsMenuItem.Enabled = LuaImp.RegisteredFunctions.Any(); + RegisteredFunctionsMenuItem.Enabled = LuaImp.GetRegisteredFunctions().Any(); } private void NewScriptMenuItem_Click(object sender, EventArgs e) @@ -840,26 +843,26 @@ namespace BizHawk.Client.EmuHawk else if (!file.Enabled && file.Thread != null) { - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); var items = SelectedItems.ToList(); foreach (var sitem in items) { var temp = sitem; - var functions = LuaImp.RegisteredFunctions.Where(lf => lf.Lua == temp.Thread).ToList(); + var functions = LuaImp.GetRegisteredFunctions().Where(lf => lf.Lua == temp.Thread).ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } UpdateRegisteredFunctionsDialog(); } - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); file.Stop(); if (Global.Config.RemoveRegisteredFunctionsOnToggle) { - LuaImp.RegisteredFunctions.ClearAll(); + LuaImp.GetRegisteredFunctions().ClearAll(); } } } @@ -879,7 +882,7 @@ namespace BizHawk.Client.EmuHawk ? item.Path : PathManager.MakeProgramRelativePath(item.Path); - item.Thread = LuaImp.SpawnCoroutine(pathToLoad); + LuaImp.SpawnAndSetFileThread(pathToLoad, item); LuaSandbox.CreateSandbox(item.Thread, Path.GetDirectoryName(pathToLoad)); }, () => { @@ -933,10 +936,10 @@ namespace BizHawk.Client.EmuHawk foreach (var item in items) { var temp = item; - var functions = LuaImp.RegisteredFunctions.Where(x => x.Lua == temp.Thread).ToList(); + var functions = LuaImp.GetRegisteredFunctions().Where(x => x.Lua == temp.Thread).ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } LuaImp.ScriptList.Remove(item); @@ -1052,7 +1055,7 @@ namespace BizHawk.Client.EmuHawk private void RegisteredFunctionsMenuItem_Click(object sender, EventArgs e) { - if (LuaImp.RegisteredFunctions.Any()) + if (LuaImp.GetRegisteredFunctions().Any()) { var alreadyOpen = false; foreach (Form form in Application.OpenForms) @@ -1209,7 +1212,7 @@ namespace BizHawk.Client.EmuHawk private void ConsoleContextMenu_Opening(object sender, CancelEventArgs e) { - RegisteredFunctionsContextItem.Enabled = LuaImp.RegisteredFunctions.Any(); + RegisteredFunctionsContextItem.Enabled = LuaImp.GetRegisteredFunctions().Any(); CopyContextItem.Enabled = OutputBox.SelectedText.Any(); ClearConsoleContextItem.Enabled = SelectAllContextItem.Enabled = diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs index 2a53a725e9..194c940646 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs @@ -17,7 +17,7 @@ namespace BizHawk.Client.EmuHawk public void UpdateValues() { - if (GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Any()) + if (GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Any()) { PopulateListView(); } @@ -46,7 +46,7 @@ namespace BizHawk.Client.EmuHawk { FunctionView.Items.Clear(); - var nlfs = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.OrderBy(x => x.Event).ThenBy(x => x.Name).ToList(); + var nlfs = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().OrderBy(x => x.Event).ThenBy(x => x.Name).ToList(); foreach (var nlf in nlfs) { var item = new ListViewItem { Text = nlf.Event }; @@ -76,7 +76,7 @@ namespace BizHawk.Client.EmuHawk foreach (int index in indices) { var guid = FunctionView.Items[index].SubItems[2].Text; - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions[guid].Call(); + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions()[guid].Call(); } } } @@ -89,8 +89,8 @@ namespace BizHawk.Client.EmuHawk foreach (int index in indices) { var guid = FunctionView.Items[index].SubItems[2].Text; - var nlf = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions[guid]; - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Remove(nlf); + var nlf = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions()[guid]; + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Remove(nlf); } PopulateListView(); @@ -109,7 +109,7 @@ namespace BizHawk.Client.EmuHawk private void RemoveAllBtn_Click(object sender, EventArgs e) { - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.ClearAll(); + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().ClearAll(); PopulateListView(); } @@ -118,7 +118,7 @@ namespace BizHawk.Client.EmuHawk var indexes = FunctionView.SelectedIndices; CallButton.Enabled = indexes.Count > 0; RemoveButton.Enabled = indexes.Count > 0; - RemoveAllBtn.Enabled = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Any(); + RemoveAllBtn.Enabled = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Any(); } private void FunctionView_KeyDown(object sender, KeyEventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 05d530176d..e26c0930ef 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -8,9 +8,11 @@ using System.ComponentModel; using System.Windows.Forms; using BizHawk.Client.Common; -using BizHawk.Emulation.Common; -using BizHawk.Common.ReflectionExtensions; +using BizHawk.Client.EmuHawk; using BizHawk.Client.EmuHawk.CoreExtensions; +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -730,6 +732,8 @@ namespace BizHawk.Client.EmuHawk return false; } + if (t == typeof(LuaConsole) && PlatformLinkedLibSingleton.RunningOnUnix) return false; + var tool = Assembly .GetExecutingAssembly() .GetTypes() diff --git a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs index c129113c37..b9afaa15a2 100644 --- a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs @@ -39,7 +39,6 @@ this.SelectAllContextMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ClearContextMenu = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1 = new MenuStripEx(); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.FileSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.SaveLogMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); @@ -149,7 +148,6 @@ // this.menuStrip1.ClickThrough = true; this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem1, this.FileSubMenu, this.EditSubMenu, this.OptionsSubMenu}); @@ -159,11 +157,6 @@ this.menuStrip1.TabIndex = 2; this.menuStrip1.Text = "menuStrip1"; // - // toolStripMenuItem1 - // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(12, 20); - // // FileSubMenu // this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -371,7 +364,6 @@ private System.Windows.Forms.GroupBox TracerBox; private MenuStripEx menuStrip1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem FileSubMenu; private System.Windows.Forms.ToolStripMenuItem SaveLogMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 8b9b8cac99..bc85c00225 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -84,6 +84,7 @@ + diff --git a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs index 5749b6b362..842eedb9b5 100644 --- a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs +++ b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs @@ -8,41 +8,24 @@ namespace BizHawk.Common.BizInvoke public class DynamicLibraryImportResolver : IImportResolver, IDisposable { private IntPtr _p; + private readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; public DynamicLibraryImportResolver(string dllName) { -#if !MONO - _p = Win32.LoadLibrary(dllName); -#else - // TODO: how can we read name remaps out of app.confg ? - _p = Libdl.dlopen(dllName, Libdl.RTLD_NOW); -#endif - if (_p == IntPtr.Zero) - { - throw new InvalidOperationException("LoadLibrary returned NULL"); - } + _p = libLoader.LoadPlatformSpecific(dllName); + if (_p == IntPtr.Zero) throw new InvalidOperationException("null pointer returned by LoadPlatformSpecific"); } public IntPtr Resolve(string entryPoint) { -#if !MONO - return Win32.GetProcAddress(_p, entryPoint); -#else - return Libdl.dlsym(_p, entryPoint); -#endif + return libLoader.GetProcAddr(_p, entryPoint); } private void Free() { - if (_p != IntPtr.Zero) - { -#if !MONO - Win32.FreeLibrary(_p); -#else - Libdl.dlclose(_p); -#endif - _p = IntPtr.Zero; - } + if (_p == IntPtr.Zero) return; + libLoader.FreePlatformSpecific(_p); + _p = IntPtr.Zero; } public void Dispose() @@ -55,30 +38,5 @@ namespace BizHawk.Common.BizInvoke { Free(); } - -#if !MONO - private static class Win32 - { - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - - [DllImport("kernel32.dll")] - public static extern bool FreeLibrary(IntPtr hModule); - } -#else - private static class Libdl - { - [DllImport("libdl.so")] - public static extern IntPtr dlopen(string filename, int flags); - [DllImport("libdl.so")] - public static extern IntPtr dlsym(IntPtr handle, string symbol); - [DllImport("libdl.so")] - public static extern int dlclose(IntPtr handle); - public const int RTLD_NOW = 2; - } -#endif } } diff --git a/BizHawk.Common/BizInvoke/MemoryBlock.cs b/BizHawk.Common/BizInvoke/MemoryBlock.cs index 6f353cbc70..fd8e57181b 100644 --- a/BizHawk.Common/BizInvoke/MemoryBlock.cs +++ b/BizHawk.Common/BizInvoke/MemoryBlock.cs @@ -9,6 +9,8 @@ namespace BizHawk.Common.BizInvoke { public sealed class MemoryBlock : IDisposable { + //TODO rewrite this class without using the external functions in Kernel32 - this may help: https://docs.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files + /// /// starting address of the memory block /// @@ -442,37 +444,10 @@ namespace BizHawk.Common.BizInvoke private static class Kernel32 { - [DllImport("kernel32.dll", SetLastError = true)] - public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize, - AllocationType flAllocationType, MemoryProtection flProtect); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool VirtualFree(UIntPtr lpAddress, UIntPtr dwSize, - FreeType dwFreeType); - [DllImport("kernel32.dll", SetLastError = true)] public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); - public enum FreeType : uint - { - DECOMMIT = 0x4000, - RELEASE = 0x8000 - } - - [Flags] - public enum AllocationType : uint - { - COMMIT = 0x1000, - RESERVE = 0x2000, - RESET = 0x80000, - RESET_UNDO = 0x1000000, - LARGE_PAGES = 0x20000000, - PHYSICAL = 0x400000, - TOP_DOWN = 0x100000, - WRITE_WATCH = 0x200000 - } - [Flags] public enum MemoryProtection : uint { diff --git a/BizHawk.Common/PlatformLinkedLibSingleton.cs b/BizHawk.Common/PlatformLinkedLibSingleton.cs new file mode 100644 index 0000000000..9a9ed2baab --- /dev/null +++ b/BizHawk.Common/PlatformLinkedLibSingleton.cs @@ -0,0 +1,86 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Common +{ + public sealed class PlatformLinkedLibSingleton + { + public static readonly bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; + + private static readonly Lazy lazy = new Lazy(() => RunningOnUnix + ? (PlatformLinkedLibManager) new UnixMonoLinkedLibManager() + : (PlatformLinkedLibManager) new Win32LinkedLibManager()); + + public static PlatformLinkedLibManager LinkedLibManager { get { return lazy.Value; } } + + private PlatformLinkedLibSingleton() {} + + public interface PlatformLinkedLibManager + { + IntPtr LoadPlatformSpecific(string dllToLoad); + IntPtr GetProcAddr(IntPtr hModule, string procName); + int FreePlatformSpecific(IntPtr hModule); + } + + public class UnixMonoLinkedLibManager : PlatformLinkedLibManager + { + // This class is copied from a tutorial, so don't git blame and then email me expecting insight. + const int RTLD_NOW = 2; + [DllImport("libdl.so.2")] + private static extern IntPtr dlopen(String fileName, int flags); + [DllImport("libdl.so.2")] + private static extern IntPtr dlerror(); + [DllImport("libdl.so.2")] + private static extern IntPtr dlsym(IntPtr handle, String symbol); + [DllImport("libdl.so.2")] + private static extern int dlclose(IntPtr handle); + public IntPtr LoadPlatformSpecific(string dllToLoad) + { + return dlopen(dllToLoad, RTLD_NOW); + } + public IntPtr GetProcAddr(IntPtr hModule, string procName) + { + dlerror(); + var res = dlsym(hModule, procName); + var errPtr = dlerror(); + if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in dlsym: {Marshal.PtrToStringAnsi(errPtr)}"); + return res; + } + public int FreePlatformSpecific(IntPtr hModule) + { + return dlclose(hModule); + } + } + + public class Win32LinkedLibManager : PlatformLinkedLibManager + { + [DllImport("kernel32.dll")] + private static extern UInt32 GetLastError(); + // was annotated `[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]` in SevenZip.NativeMethods + // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllToLoad); + // was annotated `[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]` in SevenZip.NativeMethods + // param procName was annotated `[MarshalAs(UnmanagedType.LPStr)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + // was annotated `[return: MarshalAs(UnmanagedType.Bool)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern bool FreeLibrary(IntPtr hModule); + public IntPtr LoadPlatformSpecific(string dllToLoad) + { + var p = LoadLibrary(dllToLoad); + if (p == IntPtr.Zero) throw new InvalidOperationException($"got null pointer, error code {GetLastError()}"); + return p; + } + public IntPtr GetProcAddr(IntPtr hModule, string procName) + { + return GetProcAddress(hModule, procName); + } + public int FreePlatformSpecific(IntPtr hModule) + { + return FreeLibrary(hModule) ? 1 : 0; + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs b/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs index 5454adf67c..42d57dbef6 100644 --- a/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs +++ b/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; // ReSharper disable StyleCop.SA1300 @@ -17,12 +17,12 @@ namespace BizHawk.Emulation.Common /** Creates new buffer that can hold at most sample_count samples. Sets rates so that there are blip_max_ratio clocks per sample. Returns pointer to new buffer, or NULL if insufficient memory. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr blip_new(int sample_count); /** Sets approximate input clock rate and output sample rate. For every clock_rate input clocks, approximately sample_rate samples are generated. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_set_rates(IntPtr context, double clock_rate, double sample_rate); /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, @@ -30,20 +30,20 @@ namespace BizHawk.Emulation.Common public const int BlipMaxRatio = 1 << 20; /** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_clear(IntPtr context); /** Adds positive/negative delta into buffer at specified clock time. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_add_delta(IntPtr context, uint clock_time, int delta); /** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_add_delta_fast(IntPtr context, uint clock_time, int delta); /** Length of time frame, in clocks, needed to make sample_count additional samples available. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_clocks_needed(IntPtr context, int sample_count); /** Maximum number of samples that can be generated from one time frame. */ @@ -54,24 +54,24 @@ namespace BizHawk.Emulation.Common the new time frame specifies the same clock as clock_duration in the old time frame specified. Deltas can have been added slightly past clock_duration (up to however many clocks there are in two output samples). */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_end_frame(IntPtr context, uint clock_duration); /** Number of buffered samples available for reading. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_samples_avail(IntPtr context); /** Reads and removes at most 'count' samples and writes them to 'out'. If 'stereo' is true, writes output to every other element of 'out', allowing easy interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed samples. Returns number of samples actually read. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo); - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_read_samples(IntPtr context, IntPtr @out, int count, int stereo); /** Frees buffer. No effect if NULL is passed. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_delete(IntPtr context); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index c1fdd04a45..c499855ae5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; +using BizHawk.Common; using BizHawk.Emulation.Common; using System.Text; @@ -26,17 +27,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi bool event_frameend = false; bool event_breakpoint = false; - [DllImport("kernel32.dll")] - public static extern UInt32 GetLastError(); - - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - - [DllImport("kernel32.dll")] - public static extern bool FreeLibrary(IntPtr hModule); + private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; public enum m64p_error { @@ -506,7 +497,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi } this.bizhawkCore = bizhawkCore; - CoreDll = LoadLibrary("mupen64plus.dll"); + CoreDll = libLoader.LoadPlatformSpecific("mupen64plus"); if (CoreDll == IntPtr.Zero) throw new InvalidOperationException(string.Format("Failed to load mupen64plus.dll")); @@ -605,41 +596,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi /// void connectFunctionPointers() { - m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup)); - m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreShutdown"), typeof(CoreShutdown)); - m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray)); - m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr)); - m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt)); - m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback)); - m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback)); - m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback)); - m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin)); - m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin)); - m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection)); - m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter)); - m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr)); - m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm)); - m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm)); - m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer)); - m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks)); - m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup)); - m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand)); - m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugGetState"), typeof(DebugGetState)); - m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState)); - m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugStep"), typeof(DebugStep)); - m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "MemGetSize"), typeof(MemGetSize)); - m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "init_saveram"), typeof(init_saveram)); - m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "save_saveram"), typeof(save_saveram)); - m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "load_saveram"), typeof(load_saveram)); + m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreStartup"), typeof(CoreStartup)); + m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreShutdown"), typeof(CoreShutdown)); + m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray)); + m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr)); + m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt)); + m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback)); + m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback)); + m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback)); + m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin)); + m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin)); + m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection)); + m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter)); + m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr)); + m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm)); + m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm)); + m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer)); + m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks)); + m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup)); + m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand)); + m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugGetState"), typeof(DebugGetState)); + m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState)); + m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugStep"), typeof(DebugStep)); + m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "MemGetSize"), typeof(MemGetSize)); + m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "init_saveram"), typeof(init_saveram)); + m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "save_saveram"), typeof(save_saveram)); + m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "load_saveram"), typeof(load_saveram)); - m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback)); + m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback)); - m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "GetRegisters"), typeof(GetRegisters)); + m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "GetRegisters"), typeof(GetRegisters)); - m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_read_memory"), typeof(biz_read_memory)); - m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_write_memory"), typeof(biz_write_memory)); + m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_read_memory"), typeof(biz_read_memory)); + m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_write_memory"), typeof(biz_write_memory)); - m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op)); + m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op)); } /// @@ -933,7 +924,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero); m64pCoreShutdown(); - FreeLibrary(CoreDll); + libLoader.FreePlatformSpecific(CoreDll); disposed = true; } @@ -953,18 +944,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi DetachPlugin(type); AttachedPlugin plugin; - plugin.dllHandle = LoadLibrary(PluginName); - if (plugin.dllHandle == IntPtr.Zero) - throw new InvalidOperationException(string.Format("Failed to load plugin {0}, error code: 0x{1:X}", PluginName, GetLastError())); + plugin.dllHandle = libLoader.LoadPlatformSpecific(PluginName); - plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); - plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); + plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); + plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); plugin.dllStartup(CoreDll, null, null); m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle); if (result != m64p_error.M64ERR_SUCCESS) { - FreeLibrary(plugin.dllHandle); + libLoader.FreePlatformSpecific(plugin.dllHandle); throw new InvalidOperationException(string.Format("Error during attaching plugin {0}", PluginName)); } @@ -980,7 +969,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi plugins.Remove(type); m64pCoreDetachPlugin(type); plugin.dllShutdown(); - FreeLibrary(plugin.dllHandle); + libLoader.FreePlatformSpecific(plugin.dllHandle); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 899ae0254f..fc632d8fa9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -21,8 +21,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { static QuickNES() { - Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname); - QN = BizInvoker.GetInvoker(Resolver, CallingConventionAdapters.Native); + QN = BizInvoker.GetInvoker(new DynamicLibraryImportResolver(LibQuickNES.dllname), CallingConventionAdapters.Native); QN.qn_setup_mappers(); } @@ -74,7 +73,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES } static readonly LibQuickNES QN; - static readonly DynamicLibraryImportResolver Resolver; public IEmulatorServiceProvider ServiceProvider { get; private set; } diff --git a/References/OpenTK.GLControl.dll b/References/OpenTK.GLControl.dll index 9cfe53e67ff8ca4ca26568fb59c9b8294527ca40..9d928cfb69790fe36c46f809547c1d0fe1af30f5 100644 GIT binary patch literal 45056 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 - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + From 12ad2d5b369354ea4dbf75e5103659faadb8245b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 17:31:35 -0600 Subject: [PATCH 024/440] GBHawk: Link Cable work --- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 32 +++- BizHawk.Client.EmuHawk/MainForm.Events.cs | 5 + BizHawk.Client.EmuHawk/MainForm.cs | 11 +- .../Nintendo/GBHawk/GBHawk.IEmulator.cs | 83 ++++++++++ .../GBHawkLink/GBHawkLink.IEmulator.cs | 143 ++++++++++++++++-- .../GBHawkLink/GBHawkLink.ISaveRam.cs | 55 ++++++- .../GBHawkLink/GBHawkLink.ISettable.cs | 123 ++++++++++----- .../Nintendo/GBHawkLink/GBHawkLink.cs | 44 +++--- .../GBHawkLink/GBHawkLinkControllerDeck.cs | 1 + 9 files changed, 426 insertions(+), 71 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 746d1ebd37..092908ba95 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -351,7 +351,9 @@ this.SaturnPreferencesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.DGBSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.DGBsettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.GenesisSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.DGBHawkSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.DGBHawksettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.GenesisSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.vDPViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GenesisGameGenieECDC = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator26 = new System.Windows.Forms.ToolStripSeparator(); @@ -503,7 +505,8 @@ this.N64SubMenu, this.SaturnSubMenu, this.DGBSubMenu, - this.GenesisSubMenu, + this.DGBHawkSubMenu, + this.GenesisSubMenu, this.wonderSwanToolStripMenuItem, this.AppleSubMenu, this.C64SubMenu, @@ -3177,10 +3180,25 @@ this.DGBsettingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.DGBsettingsToolStripMenuItem.Text = "Settings..."; this.DGBsettingsToolStripMenuItem.Click += new System.EventHandler(this.DgbSettingsMenuItem_Click); - // - // GenesisSubMenu - // - this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + // + // DGBHawkSubMenu + // + this.DGBHawkSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.DGBHawksettingsToolStripMenuItem}); + this.DGBHawkSubMenu.Name = "DGBHawkSubMenu"; + this.DGBHawkSubMenu.Size = new System.Drawing.Size(59, 19); + this.DGBHawkSubMenu.Text = "&GB Link"; + // + // DGBHawksettingsToolStripMenuItem + // + this.DGBHawksettingsToolStripMenuItem.Name = "DGBHawksettingsToolStripMenuItem"; + this.DGBHawksettingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.DGBHawksettingsToolStripMenuItem.Text = "Settings..."; + this.DGBHawksettingsToolStripMenuItem.Click += new System.EventHandler(this.DgbHawkSettingsMenuItem_Click); + // + // GenesisSubMenu + // + this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.vDPViewerToolStripMenuItem, this.GenesisGameGenieECDC, this.toolStripSeparator26, @@ -4504,6 +4522,8 @@ private System.Windows.Forms.ToolStripMenuItem FdsEjectDiskMenuItem; private System.Windows.Forms.ToolStripMenuItem DGBSubMenu; private System.Windows.Forms.ToolStripMenuItem DGBsettingsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem DGBHawkSubMenu; + private System.Windows.Forms.ToolStripMenuItem DGBHawksettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem GenesisSubMenu; private System.Windows.Forms.ToolStripMenuItem GenesisSettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem AtariSettingsToolStripMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 583898ae0f..e9bce5e5aa 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -2350,6 +2350,11 @@ namespace BizHawk.Client.EmuHawk DGBPrefs.DoDGBPrefsDialog(this); } + private void DgbHawkSettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "Gameboy Settings"); + } + #endregion #region GEN diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 9684d7b21e..4c02e8bf16 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -24,6 +24,7 @@ using BizHawk.Emulation.Cores.Nintendo.GBA; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.N64; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; @@ -1720,6 +1721,7 @@ namespace BizHawk.Client.EmuHawk N64SubMenu.Visible = false; SaturnSubMenu.Visible = false; DGBSubMenu.Visible = false; + DGBHawkSubMenu.Visible = false; GenesisSubMenu.Visible = false; wonderSwanToolStripMenuItem.Visible = false; AppleSubMenu.Visible = false; @@ -1802,7 +1804,14 @@ namespace BizHawk.Client.EmuHawk SaturnSubMenu.Visible = true; break; case "DGB": - DGBSubMenu.Visible = true; + if (Emulator is GBHawkLink) + { + DGBHawkSubMenu.Visible = true; + } + else + { + DGBSubMenu.Visible = true; + } break; case "WSWAN": wonderSwanToolStripMenuItem.Visible = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index 01f04f8338..e0aa0baeef 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -168,6 +168,89 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk vblank_rise = false; } + public void do_single_step() + { + // These things do not change speed in GBC double spped mode + audio.tick(); + ppu.tick(); + if (Use_MT) { mapper.Mapper_Tick(); } + + if (!HDMA_transfer) + { + // These things all tick twice as fast in GBC double speed mode + ppu.DMA_tick(); + timer.tick_1(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(ref REG_FF0F, REG_FFFF); + timer.tick_2(); + + if (double_speed) + { + ppu.DMA_tick(); + timer.tick_1(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(ref REG_FF0F, REG_FFFF); + timer.tick_2(); + } + } + else + { + timer.tick_1(); + timer.tick_2(); + cpu.TotalExecutedCycles++; + if (double_speed) + { + timer.tick_1(); + timer.tick_2(); + cpu.TotalExecutedCycles++; + } + } + + if (in_vblank && !in_vblank_old) + { + vblank_rise = true; + } + + in_vblank_old = in_vblank; + REG_FF0F_OLD = REG_FF0F; + } + + public void do_controller_check() + { + // check if new input changed the input register and triggered IRQ + byte contr_prev = input_register; + + input_register &= 0xF0; + if ((input_register & 0x30) == 0x20) + { + input_register |= (byte)(controller_state & 0xF); + } + else if ((input_register & 0x30) == 0x10) + { + input_register |= (byte)((controller_state & 0xF0) >> 4); + } + else if ((input_register & 0x30) == 0x00) + { + // if both polls are set, then a bit is zero if either or both pins are zero + byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); + input_register |= temp; + } + else + { + input_register |= 0xF; + } + + // check for interrupts + if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || + ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || + ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || + ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) + { + if (REG_FFFF.Bit(4)) { cpu.FlagI = true; } + REG_FF0F |= 0x10; + } + } + // Switch Speed (GBC only) public int SpeedFunc(int temp) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 790ab1fa06..3d0fa172cf 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { - public partial class GBHawkLink : IEmulator, IVideoProvider + public partial class GBHawkLink : IEmulator, IVideoProvider, ISoundProvider { public IEmulatorServiceProvider ServiceProvider { get; } @@ -20,6 +22,37 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); + //Update the color palette if a setting changed + if (linkSettings.Palette_L == GBHawk.GBHawk.GBSettings.PaletteType.BW) + { + L.color_palette[0] = color_palette_BW[0]; + L.color_palette[1] = color_palette_BW[1]; + L.color_palette[2] = color_palette_BW[2]; + L.color_palette[3] = color_palette_BW[3]; + } + else + { + L.color_palette[0] = color_palette_Gr[0]; + L.color_palette[1] = color_palette_Gr[1]; + L.color_palette[2] = color_palette_Gr[2]; + L.color_palette[3] = color_palette_Gr[3]; + } + + if (linkSettings.Palette_R == GBHawk.GBHawk.GBSettings.PaletteType.BW) + { + R.color_palette[0] = color_palette_BW[0]; + R.color_palette[1] = color_palette_BW[1]; + R.color_palette[2] = color_palette_BW[2]; + R.color_palette[3] = color_palette_BW[3]; + } + else + { + R.color_palette[0] = color_palette_Gr[0]; + R.color_palette[1] = color_palette_Gr[1]; + R.color_palette[2] = color_palette_Gr[2]; + R.color_palette[3] = color_palette_Gr[3]; + } + if (_tracer.Enabled) { L.cpu.TraceCallback = s => _tracer.Put(s); @@ -36,6 +69,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink HardReset(); } + bool cablediscosignalNew = controller.IsPressed("Toggle Cable"); + if (cablediscosignalNew && !_cablediscosignal) + { + _cableconnected ^= true; + Console.WriteLine("Cable connect status to {0}", _cableconnected); + LinkConnected = _cableconnected; + } + + _cablediscosignal = cablediscosignalNew; + _islag = true; GetControllerState(controller); @@ -52,8 +95,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void do_frame() { - L.do_frame(); - R.do_frame(); + L.do_controller_check(); + R.do_controller_check(); + + // advance one full frame + for (int i = 0; i < 70224; i++) + { + L.do_single_step(); + R.do_single_step(); + + // if we hit a frame boundary, update video + if (L.vblank_rise) + { + buff_L = L.GetVideoBuffer(); + L.vblank_rise = false; + } + if (R.vblank_rise) + { + buff_R = R.GetVideoBuffer(); + R.vblank_rise = false; + } + } } public void GetControllerState(IController controller) @@ -65,7 +127,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public int Frame => _frame; - public string SystemId => "GB"; + public string SystemId => "DGB"; public bool DeterministicEmulation { get; set; } @@ -89,15 +151,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public int _frameHz = 60; public int[] _vidbuffer = new int[160 * 2 * 144]; - public int[] buff_L; - public int[] buff_R; + public int[] buff_L = new int[160 * 144]; + public int[] buff_R = new int[160 * 144]; public int[] GetVideoBuffer() { // combine the 2 video buffers from the instances - buff_L = L.GetVideoBuffer(); - buff_R = R.GetVideoBuffer(); - for (int i = 0; i < 144; i++) { for (int j = 0; j < 160; j++) @@ -124,5 +183,71 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public uint[] color_palette = new uint[4]; #endregion + + #region audio + + public bool CanProvideAsync => false; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } + } + + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + short[] temp_samp_L; + short[] temp_samp_R; + + int nsamp_L; + int nsamp_R; + + L.audio.GetSamplesSync(out temp_samp_L, out nsamp_L); + R.audio.GetSamplesSync(out temp_samp_R, out nsamp_R); + + if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Left) + { + samples = temp_samp_L; + nsamp = nsamp_L; + } + else if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Right) + { + samples = temp_samp_R; + nsamp = nsamp_R; + } + else + { + samples = new short[0]; + nsamp = 0; + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + L.audio.DiscardSamples(); + R.audio.DiscardSamples(); + } + + private void GetSamples(short[] samples) + { + + } + + public void DisposeSound() + { + L.audio.DisposeSound(); + R.audio.DisposeSound(); + } + + #endregion } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs index e8a6a9d0b5..1a92caf11b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs @@ -7,9 +7,43 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { public byte[] CloneSaveRam() { - if (L.cart_RAM != null) + if ((L.cart_RAM != null) || (R.cart_RAM != null)) { - return (byte[])L.cart_RAM.Clone(); + int Len1 = 0; + int Len2 = 0; + int index = 0; + + if (L.cart_RAM != null) + { + Len1 = L.cart_RAM.Length; + } + + if (R.cart_RAM != null) + { + Len2 = R.cart_RAM.Length; + } + + byte[] temp = new byte[Len1 + Len2]; + + if (L.cart_RAM != null) + { + for (int i = 0; i < L.cart_RAM.Length; i++) + { + temp[index] = L.cart_RAM[i]; + index++; + } + } + + if (R.cart_RAM != null) + { + for (int i = 0; i < L.cart_RAM.Length; i++) + { + temp[index] = R.cart_RAM[i]; + index++; + } + } + + return temp; } else { @@ -19,7 +53,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void StoreSaveRam(byte[] data) { - Buffer.BlockCopy(data, 0, L.cart_RAM, 0, data.Length); + if ((L.cart_RAM != null) && (R.cart_RAM == null)) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length); + } + else if ((R.cart_RAM != null) && (L.cart_RAM == null)) + { + Buffer.BlockCopy(data, 0, R.cart_RAM, 0, R.cart_RAM.Length); + } + else if ((R.cart_RAM != null) && (L.cart_RAM != null)) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length); + Buffer.BlockCopy(data, L.cart_RAM.Length, R.cart_RAM, 0, R.cart_RAM.Length); + } + Console.WriteLine("loading SRAM here"); } @@ -27,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { get { - return L.has_bat & _syncSettings.L.Use_SRAM; + return (L.has_bat || R.has_bat) & linkSyncSettings.Use_SRAM; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs index dd2711ded1..75cea814bc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -13,78 +13,133 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { public GBLinkSettings GetSettings() { - return new GBLinkSettings - ( - L.GetSettings(), - R.GetSettings() - ); + return linkSettings.Clone(); } public GBLinkSyncSettings GetSyncSettings() { - return new GBLinkSyncSettings - ( - L.GetSyncSettings(), - R.GetSyncSettings() - ); + return linkSyncSettings.Clone(); } public bool PutSettings(GBLinkSettings o) { - return L.PutSettings(o.L) || R.PutSettings(o.R); + linkSettings = o; + return false; } public bool PutSyncSettings(GBLinkSyncSettings o) { - return L.PutSyncSettings(o.L) || R.PutSyncSettings(o.R); + bool ret = GBLinkSyncSettings.NeedsReboot(linkSyncSettings, o); + linkSyncSettings = o; + return ret; } - private GBLinkSettings _settings = new GBLinkSettings(); - public GBLinkSyncSettings _syncSettings = new GBLinkSyncSettings(); + private GBLinkSettings linkSettings = new GBLinkSettings(); + public GBLinkSyncSettings linkSyncSettings = new GBLinkSyncSettings(); public class GBLinkSettings { - public GBHawk.GBHawk.GBSettings L; - public GBHawk.GBHawk.GBSettings R; + [DisplayName("Color Mode")] + [Description("Pick Between Green scale and Grey scale colors")] + [DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)] + public GBHawk.GBHawk.GBSettings.PaletteType Palette_L { get; set; } - public GBLinkSettings() + [DisplayName("Color Mode")] + [Description("Pick Between Green scale and Grey scale colors")] + [DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)] + public GBHawk.GBHawk.GBSettings.PaletteType Palette_R { get; set; } + + public enum AudioSrc { - L = new GBHawk.GBHawk.GBSettings(); - R = new GBHawk.GBHawk.GBSettings(); + Left, + Right, + Both } - public GBLinkSettings(GBHawk.GBHawk.GBSettings L, GBHawk.GBHawk.GBSettings R) - { - this.L = L; - this.R = R; - } + [DisplayName("Audio Selection")] + [Description("Choose Audio Source. Both will produce Stereo sound.")] + [DefaultValue(AudioSrc.Left)] + public AudioSrc AudioSet { get; set; } public GBLinkSettings Clone() { - return new GBLinkSettings(L.Clone(), R.Clone()); + return (GBLinkSettings)MemberwiseClone(); } } public class GBLinkSyncSettings { - public GBHawk.GBHawk.GBSyncSettings L; - public GBHawk.GBHawk.GBSyncSettings R; + [DisplayName("Console Mode L")] + [Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")] + [DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)] + public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_L { get; set; } - public GBLinkSyncSettings() + [DisplayName("Console Mode R")] + [Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")] + [DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)] + public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_R { get; set; } + + [DisplayName("CGB in GBA")] + [Description("Emulate GBA hardware running a CGB game, instead of CGB hardware. Relevant only for titles that detect the presense of a GBA, such as Shantae.")] + [DefaultValue(false)] + public bool GBACGB { get; set; } + + [DisplayName("RTC Initial Time L")] + [Description("Set the initial RTC time in terms of elapsed seconds.")] + [DefaultValue(0)] + public int RTCInitialTime_L { - L = new GBHawk.GBHawk.GBSyncSettings(); - R = new GBHawk.GBHawk.GBSyncSettings(); + get { return _RTCInitialTime_L; } + set { _RTCInitialTime_L = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } - public GBLinkSyncSettings(GBHawk.GBHawk.GBSyncSettings L, GBHawk.GBHawk.GBSyncSettings R) + [DisplayName("RTC Initial Time R")] + [Description("Set the initial RTC time in terms of elapsed seconds.")] + [DefaultValue(0)] + public int RTCInitialTime_R { - this.L = L; - this.R = R; + get { return _RTCInitialTime_R; } + set { _RTCInitialTime_R = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("Timer Div Initial Time L")] + [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] + [DefaultValue(8)] + public int DivInitialTime_L + { + get { return _DivInitialTime_L; } + set { _DivInitialTime_L = Math.Min((ushort)65535, (ushort)value); } + } + + [DisplayName("Timer Div Initial Time R")] + [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] + [DefaultValue(8)] + public int DivInitialTime_R + { + get { return _DivInitialTime_R; } + set { _DivInitialTime_R = Math.Min((ushort)65535, (ushort)value); } + } + + [DisplayName("Use Existing SaveRAM")] + [Description("When true, existing SaveRAM will be loaded at boot up")] + [DefaultValue(false)] + public bool Use_SRAM { get; set; } + + [JsonIgnore] + private int _RTCInitialTime_L; + private int _RTCInitialTime_R; + [JsonIgnore] + public ushort _DivInitialTime_L; + public ushort _DivInitialTime_R; + public GBLinkSyncSettings Clone() { - return new GBLinkSyncSettings(L.Clone(), R.Clone()); + return (GBLinkSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(GBLinkSyncSettings x, GBLinkSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index c4f2ffacda..3cd8412bc7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink "GBHawkLink", "", isPorted: false, - isReleased: true)] + isReleased: false)] [ServiceNotApplicable(typeof(IDriveLight))] public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable, ISettable @@ -24,25 +24,45 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public GBHawk.GBHawk L; public GBHawk.GBHawk R; + // if true, the link cable is currently connected + private bool _cableconnected = true; + + // if true, the link cable toggle signal is currently asserted + private bool _cablediscosignal = false; + //[CoreConstructor("GB", "GBC")] public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings) { var ser = new BasicServiceProvider(this); - GBLinkSettings linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); - GBLinkSyncSettings linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); + linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); + linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); _controllerDeck = new GBHawkLinkControllerDeck(GBHawkControllerDeck.DefaultControllerName, GBHawkControllerDeck.DefaultControllerName); CoreComm = comm; + var temp_set_L = new GBHawk.GBHawk.GBSettings(); + var temp_set_R = new GBHawk.GBHawk.GBSettings(); + + var temp_sync_L = new GBHawk.GBHawk.GBSyncSettings(); + var temp_sync_R = new GBHawk.GBHawk.GBSyncSettings(); + + temp_sync_L.ConsoleMode = linkSyncSettings.ConsoleMode_L; + temp_sync_R.ConsoleMode = linkSyncSettings.ConsoleMode_R; + + temp_sync_L.DivInitialTime = linkSyncSettings.DivInitialTime_L; + temp_sync_R.DivInitialTime = linkSyncSettings.DivInitialTime_R; + temp_sync_L.RTCInitialTime = linkSyncSettings.RTCInitialTime_L; + temp_sync_R.RTCInitialTime = linkSyncSettings.RTCInitialTime_R; + L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, - game_L, rom_L, linkSettings.L, linkSyncSettings.L); + game_L, rom_L, temp_set_L, temp_sync_L); R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, - game_R, rom_R, linkSettings.R, linkSyncSettings.R); + game_R, rom_R, temp_set_R, temp_sync_R); ser.Register(this); - ser.Register(L.audio); + ser.Register(this); _tracer = new TraceBuffer { Header = L.cpu.TraceHeader }; ser.Register(_tracer); @@ -52,16 +72,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink SetupMemoryDomains(); HardReset(); - - L.color_palette[0] = color_palette_BW[0]; - L.color_palette[1] = color_palette_BW[1]; - L.color_palette[2] = color_palette_BW[2]; - L.color_palette[3] = color_palette_BW[3]; - - R.color_palette[0] = color_palette_BW[0]; - R.color_palette[1] = color_palette_BW[1]; - R.color_palette[2] = color_palette_BW[2]; - R.color_palette[3] = color_palette_BW[3]; } public void HardReset() @@ -78,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink private readonly ITraceable _tracer; - bool ILinkable.LinkConnected { get; } + public bool LinkConnected { get; private set; } private void ExecFetch(ushort addr) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs index fd2e5c7ae8..9bc1143bb4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs @@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink Name = Port1.Definition.Name, BoolButtons = Port1.Definition.BoolButtons .Concat(Port2.Definition.BoolButtons) + .Concat(new[] { "Toggle Cable" } ) .ToList() }; } From 32e4a2d9a4762d2ac643d9fa5396b588f8c9e16b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 19:24:18 -0600 Subject: [PATCH 025/440] GBHAwk: Linked play initial capability --- .../Consoles/Nintendo/GBHawk/SerialPort.cs | 15 +++++--- .../GBHawkLink/GBHawkLink.IEmulator.cs | 34 +++++++++++++++++++ .../GBHawkLink/GBHawkLink.IStatable.cs | 2 ++ .../Nintendo/GBHawkLink/GBHawkLink.cs | 2 ++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs index 64de7f5457..4aa700268c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs @@ -16,6 +16,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int serial_bits; public bool clk_internal; public int clk_rate; + public byte going_out; + public byte coming_in; public byte ReadReg(int addr) { @@ -84,16 +86,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (serial_start) { if (serial_clock > 0) { serial_clock--; } + if (serial_clock == 0) { if (serial_bits > 0) { - send_external_bit((byte)(serial_data & 0x80)); - byte temp = get_external_bit(); serial_data = (byte)((serial_data << 1) | temp); serial_bits--; + if (serial_bits == 0) { serial_control &= 0x7F; @@ -122,12 +124,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // no device connected returns 0xFF public byte get_external_bit() { - return 1; + return coming_in; } + // calling this function buts an external bit on the cable line public void send_external_bit(byte bit_send) { - + going_out = (byte)(bit_send >> 7); } public void Reset() @@ -135,6 +138,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk serial_control = 0x7E; serial_start = false; serial_data = 0x00; + going_out = 0; + coming_in = 1; } public void SyncState(Serializer ser) @@ -146,6 +151,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("serial_bits", ref serial_bits); ser.Sync("clk_internal", ref clk_internal); ser.Sync("clk_rate", ref clk_rate); + ser.Sync("going_out", ref going_out); + ser.Sync("coming_in", ref coming_in); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 3d0fa172cf..0a95188026 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -104,6 +104,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink L.do_single_step(); R.do_single_step(); + // the signal to shift out a bit is when serial_clock = 1 + if (L.serialport.serial_clock == 1) + { + if (LinkConnected) + { + L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80)); + + if ((R.serialport.clk_rate == -1) && R.serialport.serial_start) + { + R.serialport.serial_clock = 1; + R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); + R.serialport.coming_in = L.serialport.going_out; + } + + L.serialport.coming_in = R.serialport.going_out; + } + } + else if (R.serialport.serial_clock == 1) + { + if (LinkConnected) + { + R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); + + if ((L.serialport.clk_rate == -1) && L.serialport.serial_start) + { + L.serialport.serial_clock = 1; + L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80)); + L.serialport.coming_in = R.serialport.going_out; + } + + R.serialport.coming_in = L.serialport.going_out; + } + } + // if we hit a frame boundary, update video if (L.vblank_rise) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs index e078e962a9..ffd05ea99f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -57,6 +57,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink ser.Sync("Lag", ref _lagcount); ser.Sync("Frame", ref _frame); ser.Sync("IsLag", ref _islag); + ser.Sync("_cableconnected", ref _cableconnected); + ser.Sync("_cablediscosignal", ref _cablediscosignal); _controllerDeck.SyncState(ser); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index 3cd8412bc7..d007d533fb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -72,6 +72,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink SetupMemoryDomains(); HardReset(); + + LinkConnected = _cableconnected; } public void HardReset() From b82fd1fb2c403a3790a69e47c60e984bbd55b870 Mon Sep 17 00:00:00 2001 From: nattthebear Date: Fri, 4 Jan 2019 16:30:13 -0500 Subject: [PATCH 026/440] Remove bogus TODO. Absolute requirements of MemoryBlock include: 1) Ability to set and deny RWX permissions at the individual page level within the block 2) Ability to map and unmap from memory at will 3) Ability to specifiy the exact address at which the mapping occurs From the docs, I don't see any way to get at any of these from the MemoryMappedFile stuff. So that's a nonstarter. Should be easy enough to rewrite in POSIX though. --- BizHawk.Common/BizInvoke/MemoryBlock.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/BizHawk.Common/BizInvoke/MemoryBlock.cs b/BizHawk.Common/BizInvoke/MemoryBlock.cs index fd8e57181b..9c9a147533 100644 --- a/BizHawk.Common/BizInvoke/MemoryBlock.cs +++ b/BizHawk.Common/BizInvoke/MemoryBlock.cs @@ -9,8 +9,6 @@ namespace BizHawk.Common.BizInvoke { public sealed class MemoryBlock : IDisposable { - //TODO rewrite this class without using the external functions in Kernel32 - this may help: https://docs.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files - /// /// starting address of the memory block /// From 9d853d200d7830239357210408bc76b0882c5fd7 Mon Sep 17 00:00:00 2001 From: upthorn Date: Fri, 4 Jan 2019 13:57:34 -0800 Subject: [PATCH 027/440] Remove vestigial hard-coded Ecco 2 tool --- .../Api/Example/Ecco2AssistantPlugin.cs | 3456 ----------------- .../BizHawk.Client.EmuHawk.csproj | 1 - 2 files changed, 3457 deletions(-) delete mode 100644 BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs diff --git a/BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs b/BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs deleted file mode 100644 index 8764258e3d..0000000000 --- a/BizHawk.Client.EmuHawk/Api/Example/Ecco2AssistantPlugin.cs +++ /dev/null @@ -1,3456 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Drawing; - -using System.Linq; -using BizHawk.Client.ApiHawk; -using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; - -namespace BizHawk.Client.EmuHawk -{ - public sealed class Ecco2AssistantPlugin : PluginBase - { - [RequiredApi] - private IMem Mem {get; set;} - - [RequiredApi] - private IGui Gui { get; set; } - - [RequiredApi] - private IJoypad Joy { get; set; } - - [RequiredApi] - private IEmu Emu { get; set; } - - [RequiredApi] - private IGameInfo GI { get; set; } - - [RequiredApi] - private IMemorySaveState MemSS { get; set; } - - public override string Name => "Ecco 2 Assistant"; - - public override string Description => "Displays a hud with hitboxes, etc. Assists with maintaining maximum speed."; - - private enum Modes { disabled, Ecco1, Ecco2 } - private Modes _mode; - - private int _camX = 0; - private int _camY = 0; - private int _camXAddr; - private int _camYAddr; - private uint _prevF = 0; - private int _top = 0; - private int _bottom = 0; - private int _left = 0; - private int _right = 0; - private const int _signalAlpha = 255; - private int _tickerY = 81; - private int _dumpMap = 0; - private int _prevX = 0; - private int _prevY = 0; - private int _destX = 0; - private int _destY = 0; - private int _snapPast = 0; - private string _rowStateGuid = string.Empty; - private Color[] _turnSignalColors = - { - Color.FromArgb(_signalAlpha, 127, 127, 0), - Color.FromArgb(_signalAlpha, 255, 0, 0), - Color.FromArgb(_signalAlpha, 192, 0, 63), - Color.FromArgb(_signalAlpha, 63, 0, 192), - Color.FromArgb(_signalAlpha, 0, 0, 255), - Color.FromArgb(_signalAlpha, 0, 63, 192), - Color.FromArgb(_signalAlpha, 0, 192, 63), - Color.FromArgb(_signalAlpha, 0, 255, 0) - }; - private int _rseed = 1; - private int EccoRand(bool refresh = false) - { - if (refresh) - { - _rseed = (int)(Mem.ReadU16(0xFFE2F8)); - } - bool odd = (_rseed & 1) != 0; - _rseed >>= 1; - if (odd) - { - _rseed ^= 0xB400; - } - return _rseed; - } - private void DrawEccoRhomb(int x, int y, int radius, Color color, int fillAlpha = 63) - { - Point[] rhombus = { - new Point(x, y - radius), - new Point(x + radius, y), - new Point(x, y + radius), - new Point(x - radius, y) - }; - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(rhombus, color, fillColor); - } - private void DrawEccoRhomb_scaled(int x, int y, int width, int height, int rscale, int bscale, int lscale, int tscale, Color color, int fillAlpha = 63) - { - Point[] rhombus = { - new Point(x + (width << rscale), y), - new Point(x, y + (height << bscale)), - new Point(x - (width << lscale), y), - new Point(x, y - (height << tscale)) - }; - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(rhombus, color, fillColor); - } - private void DrawEccoOct(int x, int y, int r, Color color, int fillAlpha = 63) - { - var octOff = (int)(Math.Sqrt(2) * r) >> 1; - Point[] octagon = { - new Point(x, y - r), - new Point(x + octOff, y - octOff), - new Point(x + r, y), - new Point(x + octOff, y + octOff), - new Point(x, y + r), - new Point(x - octOff, y + octOff), - new Point(x - r, y), - new Point(x - octOff, y - octOff) - }; - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(octagon, color, fillColor); - } - private void DrawEccoOct_scaled(int x, int y, int xscale, int yscale, int r, Color color, int fillAlpha = 63) - { - var octOff = (int)(Math.Sin(Math.PI / 4) * r); - var xoctOff = octOff << xscale; - var yoctOff = octOff << yscale; - var xr = r << xscale; - var yr = r << yscale; - Point[] octagon = { - new Point(x, y - yr), - new Point(x + xoctOff, y - yoctOff), - new Point(x + xr, y), - new Point(x + xoctOff, y + yoctOff), - new Point(x, y + yr), - new Point(x - xoctOff, y + yoctOff), - new Point(x - xr, y), - new Point(x - xoctOff, y - yoctOff) - }; - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(octagon, color, fillColor); - } - private Point? Intersection(Point start1, Point end1, Point start2, Point end2) - { - if ((Math.Max(start1.X, end1.X) < Math.Min(start2.X, end2.X)) - || (Math.Min(start1.X, end1.X) > Math.Max(start2.X, end2.X)) - || (Math.Max(start1.Y, end1.Y) < Math.Min(start2.Y, end2.Y)) - || (Math.Min(start1.Y, end1.Y) > Math.Max(start2.Y, end2.Y))) - return null; - - - double ay_cy, ax_cx, px, py; - double dx_cx = end2.X - start2.X, - dy_cy = end2.Y - start2.Y, - bx_ax = end1.X - start1.X, - by_ay = end1.Y - start1.Y; - - double de = (bx_ax) * (dy_cy) - (by_ay) * (dx_cx); - - if (Math.Abs(de) < 0.01) - return null; - - ax_cx = start1.X - start2.X; - ay_cy = start1.Y - start2.Y; - double r = ((ay_cy) * (dx_cx) - (ax_cx) * (dy_cy)) / de; - double s = ((ay_cy) * (bx_ax) - (ax_cx) * (by_ay)) / de; - px = start1.X + r * (bx_ax); - py = start1.Y + r * (by_ay); - if ((px < Math.Min(start1.X, end1.X)) || (px > Math.Max(start1.X, end1.X)) - || (px < Math.Min(start2.X, end2.X)) || (px > Math.Max(start2.X, end2.X)) - || (py < Math.Min(start1.Y, end1.Y)) || (py > Math.Max(start1.Y, end1.Y)) - || (py < Math.Min(start2.Y, end2.Y)) || (py > Math.Max(start2.Y, end2.Y))) - return null; - return new Point((int)px, (int)py); - } - private void DrawRectRhombusIntersection(Point rectMid, Point rhombMid, int rw, int rh, int r, Color color, int fillAlpha = 63) // Octagon provided by the intersection of a rectangle and a rhombus - { - Point[] rect = - { - new Point(rectMid.X - rw, rectMid.Y + rh), - new Point(rectMid.X - rw, rectMid.Y - rh), - new Point(rectMid.X + rw, rectMid.Y - rh), - new Point(rectMid.X + rw, rectMid.Y + rh) - }; - Point[] rhombus = - { - new Point(rhombMid.X - r, rhombMid.Y), - new Point(rhombMid.X, rhombMid.Y - r), - new Point(rhombMid.X + r, rhombMid.Y), - new Point(rhombMid.X, rhombMid.Y + r) - }; - List finalShape = new List(); - foreach (Point p in rect) - { - if (Math.Abs(p.X - rhombMid.X) + Math.Abs(p.Y - rhombMid.Y) <= r) - finalShape.Add(p); - } - foreach (Point p in rhombus) - { - if ((Math.Abs(p.X - rectMid.X) <= rw) && (Math.Abs(p.Y - rectMid.Y) <= rh)) - finalShape.Add(p); - } - for (int i = 0; i < 5; i++) - { - Point? p = Intersection(rhombus[i & 3], rhombus[(i + 1) & 3], rect[i & 3], rect[(i + 1) & 3]); - if (p.HasValue) finalShape.Add(p.Value); - p = Intersection(rhombus[i & 3], rhombus[(i + 1) & 3], rect[(i + 1) & 3], rect[(i + 2) & 3]); - if (p.HasValue) finalShape.Add(p.Value); - } - double mX = 0; - double my = 0; - foreach (Point p in finalShape) - { - mX += p.X; - my += p.Y; - } - mX /= finalShape.ToArray().Length; - my /= finalShape.ToArray().Length; - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(finalShape.OrderBy(p => Math.Atan2(p.Y - my, p.X - mX)).ToArray(), color, fillColor); - } - private void DrawEccoTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color, int fillAlpha = 63) - { - Color? fillColor = null; - Point[] triPoints = - { - new Point(x1, y1), - new Point(x2, y2), - new Point(x3, y3) - }; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawPolygon(triPoints, color, fillColor); - } - private void DrawBoxMWH(int x, int y, int w, int h, Color color, int fillAlpha = 63) - { - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawRectangle(x - w, y - h, w << 1, h << 1, color, fillColor); - } - private void DrawBox(int x, int y, int x2, int y2, Color color, int fillAlpha = 63) - { - Color? fillColor = null; - if (fillAlpha > 0) fillColor = Color.FromArgb(fillAlpha, color); - Gui.DrawBox(x, y, x2, y2, color, fillColor); - } - private void Print_Text(string message, int x, int y, Color color) - { - Gui.DrawText(x, y, message, color, null); - } - private void PutText(string message, int x, int y, int xl, int yl, int xh, int yh, Color bg, Color fg) - { - xl = Math.Max(xl, 0); - yl = Math.Max(yl, 0); - xh = Math.Min(xh + 639, 639); - yh = Math.Min(yh + 441, 441); - xh -= 4 * message.Length; - x = x - ((5 * (message.Length - 1)) / 2); - y -= 3; -// x = Math.Min(Math.Max(x, Math.Max(xl, 1)), Math.Min(xh, 638 - 4 * (int)message.Length)); -// y = Math.Min(Math.Max(y - 3, Math.Max(yl, 1)), yh); - int[] xOffset = { -1, -1, -1, 0, 1, 1, 1, 0 }; - int[] yOffset = { -1, 0, 1, 1, 1, 0, -1, -1 }; - for (int i = 0; i < 8; i++) - Print_Text(message, x + xOffset[i], y + yOffset[i], bg); - Print_Text(message, x, y, fg); - } - private void TickerText(string message, Color? fg = null) - { - if (_dumpMap == 0) - Gui.Text(1, _tickerY, message, fg); - _tickerY += 16; - } - private void EccoDraw3D() - { - int CamX = (Mem.ReadS32(0xFFD5E0) >> 0xC) - _left; - int CamY = (Mem.ReadS32(0xFFD5E8) >> 0xC) + _top; - int CamZ = (Mem.ReadS32(0xFFD5E4) >> 0xC) + _top; - uint curObj = Mem.ReadU24(0xFFD4C1); - while (curObj != 0) - { - int Xpos = (Mem.ReadS32(curObj + 0x6) >> 0xC); - int Ypos = (Mem.ReadS32(curObj + 0xE) >> 0xC); - int Zpos = (Mem.ReadS32(curObj + 0xA) >> 0xC); - int Xmid = 160 + (Xpos - CamX); - int Ymid = 112 - (Ypos - CamY); - int Zmid = _top + 112 - (Zpos - CamZ); - uint type = Mem.ReadU32(curObj + 0x5A); - int width, height, depth = height = width = 0; - if (type == 0xD4AB8) // 3D poison Bubble - { - depth = 0x10; - int radius = 8; - width = radius; - DrawEccoOct(Xmid, Ymid, radius, Color.Lime); - DrawBoxMWH(Xmid, Zmid, width, depth, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - } - else if (type == 0xD817E)// 3D Ring - { - depth = 8; - if (Mem.ReadU32(0xFFB166) < 0x1800) depth = 4; - int radius = 32; - width = radius; - DrawEccoOct(Xmid, Ymid, radius, (Mem.ReadS16(curObj + 0x62) == 0) ? Color.Orange : Color.Gray); - DrawBoxMWH(Xmid, Zmid, width, depth, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red, 0); - TickerText($"{Mem.ReadS32(curObj + 0x6) / 4096.0:0.######}:{Mem.ReadS32(curObj + 0xE) / 4096.0:0.######}:{Mem.ReadS32(curObj + 0xA) / 2048.0:0.######}:{Mem.ReadByte(curObj + 0x72)}",Color.Lime); - } - else if (type == 0xD49CC) // Vines collisions are based on draw position, which is a fucking pain in the ass to calculate - { - int Xvel = (Mem.ReadS32(curObj + 0x3A) - Mem.ReadS32(curObj + 0x6)); - int Zvel = (Mem.ReadS32(curObj + 0x3E) - Mem.ReadS32(curObj + 0xA)); - int dx = Mem.ReadS32(0xFFD5E0) - Mem.ReadS32(0xFFD5C8) >> 3; - int dy = Mem.ReadS32(0xFFD5E8) - Mem.ReadS32(0xFFD600) >> 3; - int dz = Mem.ReadS32(0xFFD5E4) - Mem.ReadS32(0xFFD5CC); - var chargeCount = Mem.ReadByte(0xFFB19B); - if (chargeCount == 0) - { - dz >>= 2; - } - else if ((chargeCount > 0x20) || (chargeCount <= 0x10)) - { - dz >>= 3; - } - else if (chargeCount > 0x10) - { - dz >>= 4; - } - if (Mem.ReadByte(curObj + 0x64) == 0) - { - Xvel >>= 0xA; - Zvel >>= 9; - } - else - { - Xvel >>= 9; - Zvel >>= 0xA; - } - Xvel += Mem.ReadS32(curObj + 0x2E); - Zvel += Mem.ReadS32(curObj + 0x32); - Zpos = (Mem.ReadS32(curObj + 0x26) + dz - Mem.ReadS32(0xFFD5E4)) >> 0xB; - if ((Zpos < 0x600) && (Zpos > 0)) - { - Zpos += 0x20; - int Xcur, Xmax, Ycur, Ymax; - int Zpos2 = (Mem.ReadS32(curObj + 0xA) + Zvel + dz - Mem.ReadS32(0xFFD5E4)) >> 0xB; - Zpos2 = Math.Max(Zpos2 + 0x20, 1); - if (Mem.ReadS16(curObj + 0x62) != 0) - { - Xmid = Mem.ReadS32(curObj + 0x6) + dx + Xvel - Mem.ReadS32(0xFFD5E0); - if (Math.Abs(Xmid) > 0x400000) - continue; - Xpos = Mem.ReadS32(curObj + 0x22) + dx - Mem.ReadS32(0xFFD5E0); - if (Math.Abs(Xpos) > 0x400000) - continue; - Xcur = (Xmid << 2) / Zpos2 + (Xmid >> 5) + 0xA000 + (Xmid >> 5); - Xmax = (Xpos << 2) / Zpos + (Xpos >> 5) + 0xA000 + (Xpos >> 5); - } - else - { - Xcur = 0; - Xmax = 256; - } - Ymid = Mem.ReadS32(0xFFD5E8) + dy - Mem.ReadS32(curObj + 0xE); - Ycur = ((Ymid << 3) / Zpos2) + 0x6000; - Ypos = Mem.ReadS32(0xFFD5E8) + dy - Mem.ReadS32(curObj + 0x2A); - Ymax = ((Ypos << 3) / Zpos) + 0x6000; - dx = Xmax - Xcur; - dy = Ymax - Ycur; - int asindx = Math.Abs(dx >> 6) & 0xFFFF; - int asindy = Math.Abs(dy >> 6) & 0xFFFF; - int ang; - if (asindx == asindy) - { - if (dx > 0) - { - if (dy > 0) - { - ang = 0x20; - } - else - { - ang = 0xE0; - } - } - else - { - if (dy > 0) - { - ang = 0x60; - } - else - { - ang = 0xA0; - } - } - } - else - { - if (asindx > asindy) - { - asindy <<= 5; - asindy += asindx - 1; - asindy &= 0xFFFF; - asindy /= asindx; - } - else - { - asindx <<= 5; - asindx += asindy - 1; - asindx &= 0xFFFF; - asindx /= asindy; - asindy = 0x40 - asindx; - } - if (dx > 0) - { - if (dy > 0) - { - ang = asindy; - } - else - { - ang = 0xff - asindy; - } - } - else - { - if (dy > 0) - { - ang = 0x7f - asindy; - } - else - { - ang = 0x81 + asindy; - } - } - } - Xcur += Mem.ReadS8(0x2CC8 + ang) << 6; - Ycur += Mem.ReadS8(0x2BC8 + ang) << 6; - var dSml = Math.Abs(dx); - var dBig = Math.Abs(dy); - if (dBig < dSml) - { - dSml ^= dBig; - dBig ^= dSml; - dSml ^= dBig; - } - int OctRad = (dBig + (dSml >> 1) - (dSml >> 3)); - int i = Math.Max(((OctRad >> 8) + 0x1F) >> 5, 1); - dx /= i; - dy /= i; - - Zmid = (Mem.ReadS32(curObj + 0xA) + Mem.ReadS32(curObj + 0x26)) >> 1; - Zmid >>= 0xC; - Zmid = 112 + _top - (Zmid - CamZ); - do - { - i--; - DrawEccoRhomb((Xcur >> 8) + _left, (Ycur >> 8) + _top, 8, Color.Lime); - DrawBoxMWH((Xcur >> 8) + _left, Zmid, 8, 0x10, Color.Blue); - Xcur += dx; - Ycur += dy; - } while (i >= 0); - DrawBoxMWH((Mem.ReadS32(0xFFB1AA) >> 8) + _left, (Mem.ReadS32(0xFFB1AE) >> 8) + _top, 1, 1, Color.Lime, 0); - } - } - else if ((type == 0xD3B40) || (type == 0xD3DB2)) // 3D Shark and Jellyfish - { - width = (Mem.ReadS32(curObj + 0x12) >> 0xC); - height = (Mem.ReadS32(curObj + 0x1A) >> 0xC); - depth = (Mem.ReadS32(curObj + 0x16) >> 0xC); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); - DrawBoxMWH(Xmid, Zmid, width, depth, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - } - else if ((type == 0xD4028) || (type == 0xD4DBA)) // 3D Eagle and 3D Shell - { - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - } - else if (type == 0xD4432) // 3D Sonar Blast - { - DrawEccoOct(Xmid, Ymid, 48, Color.Orange); - DrawEccoOct(Xmid, Ymid, 32, Color.Lime); - DrawBoxMWH(Xmid, Zmid, 32, 32, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - } - else if (type == 0xD463A) // 3D Homing Bubble - { - DrawEccoOct(Xmid, Ymid, 48, Color.Orange); - DrawEccoOct(Xmid, Ymid, 32, Color.Lime); - DrawBoxMWH(Xmid, Zmid, 32, 32, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - } - else if ((type == 0xD37CE) || (type == 0xD4214) || (type == 0xD3808)) // bubbles, splashes, gfx sprites - { - width = height = depth = 0; - } - else - { - if (curObj != 0xFFB134) - { - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Lime, 0); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Blue, 0); - PutText(type.ToString("X8"), Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); - PutText(curObj.ToString("X8"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); - } - else - { - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange); - DrawBoxMWH(Xmid, Zmid, 1, 1, Color.Red); - } - } - curObj = Mem.ReadU24(curObj+1); - } - } - private void EccoDrawBoxes() - { - // CamX-=8; - int Width2, Height2; - //Ecco HP and Air - int i = 0; - int HP = Mem.ReadS16(0xFFAA16) << 3; - int air = Mem.ReadS16(0xFFAA18); - Color color; - int off = 0; - for (int j = 0; j < air; j++) - { - if (j - off == 448) - { - i++; off += 448; - } - color = Color.FromArgb(j >> 2, j >> 2, j >> 2); - Gui.DrawLine(_left - 32, j - off, _left - 17, j - off, color); - } - for (int j = 0; j < HP; j += 8) - { - color = Color.FromArgb(Math.Max(0x38 - (j >> 3),0), 0, Math.Min(j >> 1,255)); - Gui.DrawRectangle(_left - 16, j, 15, 7, color, color); - } - - //Asterite - uint type = Mem.ReadU32(0xFFD440); - uint curObj = 0; - int Xpos, Xpos2, Ypos, Ypos2, Xmid, Ymid, X, X2, Y, Y2; - Xpos = Ypos = Xpos2 = Ypos2 = Xmid = Ymid = X = X2 = Y = Y2 = 0; - if (type == 0xB119A) - { - curObj = Mem.ReadU24(Mem.ReadU24(0xFFD429)+5); - while (curObj != 0) - { - Xpos = Mem.ReadS16(curObj + 0x3C); - Xpos2 = Mem.ReadS16(curObj + 0x24); - Ypos = Mem.ReadS16(curObj + 0x40); - Ypos2 = Mem.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - if (Mem.ReadU8(curObj + 0x71) != 0) - { - DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); - DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); - } - curObj = Mem.ReadU24(curObj + 5); - } - if ((Mem.ReadU8(0xFFA7D0) == 30)) - { - curObj = Mem.ReadU24(0xFFD425); - if ((curObj != 0) && (Mem.ReadU32(curObj + 8) != 0)) - { - Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; - Ypos = Mem.ReadS16(curObj + 0x20) - _camY; - DrawEccoOct(Xpos, Ypos, 20, Color.Orange); - } - } - } - else if (type == 0xB2CB8) - { - curObj = Mem.ReadU24(Mem.ReadU24(0xFFD429) + 5); - while (curObj != 0) - { - Xpos = Mem.ReadS16(curObj + 0x3C); - Xpos2 = Mem.ReadS16(curObj + 0x24); - Ypos = Mem.ReadS16(curObj + 0x40); - Ypos2 = Mem.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - if (Mem.ReadU8(curObj + 0x71) != 0) - { - if (Mem.ReadByte(0xFFA7D0) != 0x1F) - { - DrawEccoOct(Xpos, Ypos, 40, Color.Lime); - DrawEccoOct(Xpos2, Ypos2, 40, Color.Lime); - } - DrawEccoOct(Xpos, Ypos, 48, Color.Blue, 16); - DrawEccoOct(Xpos2, Ypos2, 48, Color.Blue, 16); - } - curObj = Mem.ReadU24(curObj + 5); - } - } - //aqua tubes - curObj = Mem.ReadU24(0xFFCFC5); - while (curObj != 0) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2= Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2= Mem.ReadS16(curObj + 0x38); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - // displayed = false; - type = Mem.ReadU8(curObj + 0x7E); - switch (type) - { - case 0x15: - case 0x18: - case 0x19: - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.Purple); - break; - case 0x1A: - case 0x1D: - case 0x20: - case 0x21: - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.Purple); - break; - case 0x1F: - case 0x22: - case 0x23: - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.Purple); - break; - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.Purple); - break; - case 0x2B: - Point[] trapPoints = - { - new Point(Xpos, Ymid), - new Point(Xpos + (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2, Ymid) - }; - Gui.DrawPolygon(trapPoints, Color.Purple, Color.FromArgb(63, Color.Purple)); - break; - default: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Purple); - if (type != 0x10) - PutText(type.ToString("X2"), Xmid, Ymid, 1, 1, -1, -1, Color.Red, Color.Blue); - break; - } - curObj = Mem.ReadU24(curObj+1); - } - //walls - curObj = Mem.ReadU24(0xFFCFC1); - while (curObj != 0) - { - Xmid = Mem.ReadS16(curObj + 0x24); - Xmid = Mem.ReadS16(curObj + 0x28); - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2= Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2= Mem.ReadS16(curObj + 0x38); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - int colltype = Mem.ReadS8(curObj + 0x7E); - switch (colltype) - { - case 0x10: - case 0x2D: - case 0x2E: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x11: - Xmid = (Xpos + Xpos2) >> 1; - Xpos2 = Xmid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x12: - Xmid = (Xpos + Xpos2) >> 1; - Xpos = Xmid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ypos, Xpos, Ypos2, Color.PowderBlue); - break; - case 0x13: - Ymid = (Ypos + Ypos2) >> 1; - Ypos = Ymid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.PowderBlue); - break; - case 0x14: - Ymid = (Ypos + Ypos2) >> 1; - Ypos2 = Ymid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); - break; - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); - break; - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63,Color.Yellow)); - Gui.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); - break; - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63,Color.Yellow)); - Gui.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); - break; - case 0x29: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - Gui.DrawLine(Xpos , Ypos, Xpos , Ypos2, Color.Black); - Gui.DrawLine(Xpos2, Ypos, Xpos2, Ypos2, Color.Black); - break; - case 0x2A: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); - break; - case 0x2B: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - Point[] trapPoints = - { - new Point(Xpos, Ymid), - new Point(Xpos + (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2, Ymid) - }; - Gui.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); - //Gui.DrawLine(Xpos, Ymid, Xpos2, Ymid, Color.Yellow); - break; - default: - DrawEccoRhomb_scaled(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); - break; - } - curObj = Mem.ReadU24(curObj+1); - } - //inanimate objects - curObj = Mem.ReadU24(0xFFCFBD); - while (curObj != 0) - { - type = Mem.ReadU32(curObj + 0xC); - int colltype = Mem.ReadS8(curObj + 0x7E); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - int Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - int Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - if (type == 0x9CE3A) //Remnant Stars - { - uint subObj = Mem.ReadU24(curObj + 0x5); - uint anim = Mem.ReadU16(curObj + 0x6C); - if ((anim <= 7) && (subObj == 0xFFA9D4)) - { - DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); - PutText($"{((7 - anim) * 4) - ((Mem.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Lime, Color.Blue); - } - } - else if ((type == 0x9CC06) || (type == 0x9CA10)) - { - Xvec = ((Mem.ReadS32(curObj + 0x24) + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Mem.ReadS32(curObj + 0x28) + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - } - else if (type == 0x9B5D8) - { - Xvec = Xmid; - Yvec = Ymid; - } - else if (type == 0xC0152) // Vortex Future Vertical Gate - { - Xvec = Mem.ReadS16(curObj + 0x1C) - _camX; - Yvec = (Mem.ReadS32(curObj + 0x20) + Mem.ReadS32(curObj + 0x60) >> 16) - _camY; - Gui.DrawLine(Xmid, 0, Xmid, 448, Color.PowderBlue); - DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - } - else if (type == 0xC3330) // City Of Forever Horizontal Gate Slave - { - Xvec = (Mem.ReadS32(curObj + 0x1C) + Mem.ReadS32(curObj + 0x5C) >> 16) - _camX; - Yvec = Mem.ReadS16(curObj + 0x20) - _camY; - DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - } - else if (type == 0xC35B0) // City Of Forever Horizontal Gate Master - { - var mode = Mem.ReadByte(curObj + 0x15); - var tmpx = Xpos; - Xpos = Mem.ReadS32(curObj + 0x1C); - Xvec = (Xpos + Mem.ReadS32(curObj + 0x5C) >> 16) - _camX; - Xpos >>= 16; Xpos -= _camX; - Yvec = Mem.ReadS16(curObj + 0x20) - _camY; - if ((mode == 1) || (mode == 3)) - { - DrawEccoOct(Xpos, Yvec, 128, Color.Orange); - } - Xpos = tmpx; - DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - } - else if (type == 0xC343A) // City Of Forever Vertical Gate - { - var mode = Mem.ReadByte(curObj + 0x15); - if ((mode == 1) || (mode == 3)) - { - DrawEccoOct(Xmid, Ymid, 128, Color.Orange); - } - Xvec = Mem.ReadS16(curObj + 0x1C) - _camX; - Yvec = (Mem.ReadS32(curObj + 0x20) + Mem.ReadS32(curObj + 0x60) >> 16) - _camY; - DrawBoxMWH(Xvec, Yvec, 1, 1, Color.Blue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - } - else if (type == 0xA579A) // Antigrav Ball - { - DrawEccoOct(Xmid, Ymid, Mem.ReadS16(curObj + 0x4C), (Mem.ReadU16(0xFFA7C8) & 7) == 7 ? Color.Blue : Color.Gray); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - Xpos = Ypos = Xpos2 = Ypos2 = _camX - 128; - } - else if (type == 0xDF4E2) // Moray Abyss Conch Shell - { - Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; - Ypos = Mem.ReadS16(curObj + 0x20) - _camY; - DrawBox(Xpos - 96, 0 - _camY, Xpos + 96, Mem.ReadS16(0xFFA7AC) - _camY - 64, Color.Orange, 0); - var mode = Mem.ReadByte(curObj + 0x15); - var modeTimer = Mem.ReadS16(curObj + 0x6E); - var Xvel1 = Mem.ReadS32(curObj + 0x54) / 65536.0; - var Yvel1 = Mem.ReadS32(curObj + 0x58) / 65536.0; - var Xvel2 = Mem.ReadS32(curObj + 0x5C) / 65536.0; - var Yvel2 = Mem.ReadS32(curObj + 0x60) / 65536.0; - TickerText($"{mode}:{modeTimer}:{Mem.ReadS16(0xFFA7AC) - 64 - Ymid - _camY}", Color.Red); - TickerText($"{Xvel1:0.######}:{Yvel1:0.######}", Color.Red); - TickerText($"{Xvel2:0.######}:{Yvel2:0.######}", Color.Red); - TickerText($"{Xvel1 + Xvel2:0.######}:{Yvel1 + Yvel2:0.######}", Color.Red); - switch (mode) - { - case 0: - Xpos2 = Math.Abs(Xmid - Xpos); - if (Xpos2 > 0x48) - { - Xpos2 = (0x60 - Xpos2) << 1; - Ypos2 = Ymid + Xpos2; - } - else - { - Ypos2 = Ymid - (Xpos2 >> 1) + 0x60; - } - DrawBoxMWH(Xpos, Ypos2, 1, 1, Color.Gray, 0); - DrawBoxMWH(Xpos, 112 + _top, 72, 224, (modeTimer <= 1) ? Color.Orange : Color.Gray, 0); - break; - case 1: - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Orange, 0); - Xpos2 = Mem.ReadS32(0xFFAA1A) - Mem.ReadS32(curObj + 0x24); - Ypos2 = Mem.ReadS32(0xFFAA1E) - Mem.ReadS32(curObj + 0x28); - var dSml = Math.Abs(Xpos2); - var dBig = Math.Abs(Ypos2); - if (dBig < dSml) - { - dSml ^= dBig; - dBig ^= dSml; - dSml ^= dBig; - } - var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; - Xpos2 = (int)(Xpos2 * (256.0 / (rad+1))) >> 20; - Ypos2 = (int)(Ypos2 * (256.0 / (rad+1))) >> 20; - Gui.DrawLine(Xmid, Ymid, Xmid + Xpos2, Ymid + Ypos2, Color.Gray); - TickerText($"{Xpos2 / 512.0:0.######}:{Ypos2 / 512.0:0.######}", Color.Red); - break; - case 2: - TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); - break; - } - } - else if ((type == 0xC57A6) || (type == 0xDEE3C) || (type == 0xDF8A0) || (type == 0xDFA98) - || (type == 0xA0BE4) || (type == 0x9FEB2) || (type == 0xA5670) || (type == 0xAEC1A) - || (type == 0xA6C4A) || (type == 0xAB65A) || (type == 0x9F2EC)) { } - else - { - PutText($"{type:X5}:{Mem.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.Lime, Color.Blue); - PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.Lime, Color.Blue); - } - colltype = Mem.ReadS8(curObj + 0x7E); - switch (colltype) - { - case 0x10: - case 0x2D: - case 0x2E: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x11: - Xmid = (Xpos + Xpos2) >> 1; - Xpos2 = Xmid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x12: - Xmid = (Xpos + Xpos2) >> 1; - Xpos = Xmid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x13: - Ymid = (Ypos + Ypos2) >> 1; - Ypos = Ymid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x14: - Ymid = (Ypos + Ypos2) >> 1; - Ypos2 = Ymid; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xmid, Ypos2, Xpos2, Ymid, Color.PowderBlue); - break; - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos2, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ymid, Xmid, Ypos2, Color.PowderBlue); - break; - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xpos, Ymid, Xmid, Ypos, Color.PowderBlue); - break; - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - DrawEccoTriangle(Xmid, Ymid, Xmid, Ypos, Xpos2, Ymid, Color.FromArgb(63, Color.Yellow)); - Gui.DrawLine(Xmid, Ypos, Xpos2, Ymid, Color.PowderBlue); - break; - case 0x2A: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Black)); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos, Color.Black); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos2, Color.Black); - break; - case 0x2B: - Xmid = (Xpos + Xpos2) >> 1; - Ymid = (Ypos + Ypos2) >> 1; - Point[] trapPoints = - { - new Point(Xpos, Ymid), - new Point(Xpos + (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2 - (Ymid - Ypos >> 1), Ypos), - new Point(Xpos2, Ymid) - }; - Gui.DrawPolygon(trapPoints, Color.PowderBlue, Color.FromArgb(63, Color.PowderBlue)); - break; - case 0x2C: - break; - default: - DrawEccoRhomb_scaled(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x44), (colltype & 1), (colltype & 2) >> 1, (colltype & 4) >> 2, (colltype & 8) >> 3, Color.PowderBlue); - break; - } - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - curObj = Mem.ReadU24(curObj+1); - } - //animate objects - if (_mode == Modes.Ecco2) - curObj = Mem.ReadU24(0xFFCFB9); - else - curObj = Mem.ReadU24(0xFFD829); - while (curObj != 0) - { - type = 0; - switch (_mode) { - case Modes.Ecco2: - { - uint flags = Mem.ReadU16(curObj + 0x10); - int Xvec = 0; - int Yvec = 0; - //if ((flags & 0x2000) || !(flags & 2)); - HP = Mem.ReadS8(curObj + 0x7B); - type = Mem.ReadU32(curObj + 0xC); - if ((type == 0xA1FE6) || (type == 0xA208E) // Chain link creatures such as vortex worm, magic arm, etc - || (type == 0xA2288) || (type == 0xA27A4) || (type == 0xA2BB0) || (type == 0xA2C50)) - { - uint subObj = curObj; - while (subObj != 0) - { - Xpos = Mem.ReadS32(subObj + 0x24); - Ypos = Mem.ReadS32(subObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - if (Mem.ReadS16(subObj + 0x44) == Mem.ReadS16(subObj + 0x48)) - { - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Cyan, 0); - } - else - { - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Lime, 0); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.Blue, 0); - } - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - subObj = Mem.ReadU24(subObj + 5); - } - if (HP > 2) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); - } - } - else if ((type == 0xB7486) || (type == 0xB864E) //Chain link creatures such as eels and worms - || (type == 0xB8A64) || (type == 0xB8C1A) - || (type == 0xB904A) || (type == 0xB9728) || (type == 0xB9B6A) || (type == 0xBA52E) - || (type == 0xBA66E) || (type == 0xE0988) || (type == 0xA18E2) || (type == 0xE069A)) - { - uint subObj = curObj; - while (subObj != 0) - { - Xpos = Mem.ReadS32(subObj + 0x24); - Ypos = Mem.ReadS32(subObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - if (Mem.ReadS16(subObj + 0x44) == Mem.ReadS16(subObj + 0x48)) - { - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.White, 0); - } - else - { - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x44), Color.Lime, 0); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.FromArgb(255, 0, 127)); - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(subObj + 0x48), Color.Magenta, 0); - } - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - if (type == 0xBA66E) - { - DrawEccoOct(Xpos, Ypos, 32, Color.Blue, 16); - if (subObj == curObj) - { - var mode = Mem.ReadByte(subObj + 0x15); - TickerText($"{Mem.ReadByte(subObj + 0x14)}:{mode}:{Mem.ReadByte(subObj + 0x70)}", Color.Red); - TickerText($"{Mem.ReadS32(subObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); - TickerText($"{Mem.ReadS32(subObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x50) / 65536.0:0.######}", Color.Red); - switch (mode) - { - case 0: - case 2: - case 4: - Xpos2 = Mem.ReadS32(0xFFAA22) - Mem.ReadS32(subObj + 0x24); - Ypos2 = Mem.ReadS32(0xFFAA26) - Mem.ReadS32(subObj + 0x28); - var dSml = Math.Abs(Xpos2); - var dBig = Math.Abs(Ypos2); - if (dBig < dSml) - { - dSml ^= dBig; - dBig ^= dSml; - dSml ^= dBig; - } - var rad = (dBig + (dSml >> 1) - (dSml >> 3)) / 65536.0; - Xpos2 = (int)(Xpos2 * (256.0 / (rad + 1))) >> 20; - Ypos2 = (int)(Ypos2 * (256.0 / (rad + 1))) >> 20; - Gui.DrawLine(Xpos, Ypos, Xpos + Xpos2, Ypos + Ypos2, Color.Red); - break; - default: - break; - - } - } - } - else if ((type == 0xBA52E) && (subObj == Mem.ReadU24(curObj + 0x1D))) - { - DrawEccoOct(Xpos, Ypos, 32, (Mem.ReadByte(subObj + 0x70) == 0) ? Color.Blue : Color.Gray, 16); - var mode = Mem.ReadByte(curObj + 0x15); - TickerText($"{Mem.ReadByte(curObj + 0x14)}:{mode}:{Mem.ReadS16(curObj + 0x6E)}:{Mem.ReadByte(subObj + 0x70)}", Color.Red); - TickerText($"{Mem.ReadS32(subObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(subObj + 0x58) / 65536.0:0.######}", Color.Red); - TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Red); - } - else if (type == 0xE0988) - { - DrawEccoOct(Xpos, Ypos, 48, Color.FromArgb(64, Color.Blue), 16); - } - if (HP > 2) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); - } - subObj = Mem.ReadU24(subObj + 5); - } - } - else if (type == 0xB7DF4) - { - Xpos = Mem.ReadS32(curObj + 0x24); - Ypos = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, 26, Color.PowderBlue); - DrawEccoOct(Xpos, Ypos, 26, Color.White); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec); - } - else if (type == 0xE47EE) - { - uint subObj = Mem.ReadU24(curObj + 5); - while (subObj != 0) - { - Xpos = Mem.ReadS32(subObj + 0x1C); - Ypos = Mem.ReadS32(subObj + 0x20); - Xvec = ((Xpos + Mem.ReadS32(subObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(subObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, ((Mem.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.White); - DrawEccoOct(Xpos, Ypos, ((Mem.ReadS16(subObj + 0x2C) & 0xFFFF) >> 1) + 16, Color.Yellow, 0); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - subObj = Mem.ReadU24(subObj + 5); - } - } - else if (type == 0xDBE64) // Medusa Boss - { - uint subObj = curObj; - uint next; - do - { - next = Mem.ReadU24(subObj + 5); - if (next != 0) subObj = next; - } while (next != 0); - Xpos = Mem.ReadS16(subObj + 0x2C); - Xpos2 = Mem.ReadS16(subObj + 0x34); - Ypos = Mem.ReadS16(subObj + 0x30); - Ypos2 = Mem.ReadS16(subObj + 0x38); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - DrawEccoOct(Xpos, Ypos, 32, Color.Red); - DrawEccoOct(Xpos2, Ypos2, 32, Color.Red); - Xpos = Mem.ReadS32(curObj + 0x24); - Ypos = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - var octOff = (int)(Math.Sqrt(2) * 60) >> 1; - Point[] hemiOctPoints = - { - new Point(Xpos - 60, Ypos), - new Point(Xpos - octOff, Ypos - octOff), - new Point(Xpos, Ypos - 60), - new Point(Xpos + octOff, Ypos - octOff), - new Point(Xpos + 60, Ypos) - }; - Gui.DrawPolygon(hemiOctPoints, Color.Cyan, Color.FromArgb(0x3F, Color.Cyan)); - for (int l = 0; l < 4; l++) - { - Gui.DrawLine(hemiOctPoints[l].X, hemiOctPoints[l].Y, hemiOctPoints[l + 1].X, hemiOctPoints[l + 1].Y, Color.Cyan); - } - DrawBoxMWH(Xpos, Ypos + 12, 52, 12, Color.Cyan); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - } - else if (type == 0xDCEE0) // Globe Holder boss - { - uint subObj; - var mode = Mem.ReadByte(curObj + 0x15); - if (mode < 4) - { - subObj = Mem.ReadU24(curObj + 9); - while (subObj != 0) - { - Xmid = Mem.ReadS32(subObj + 0x24); - Ymid = Mem.ReadS32(subObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(subObj + 0x54) + Mem.ReadS32(subObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(subObj + 0x58) + Mem.ReadS32(subObj + 0x60)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawEccoOct(Xmid, Ymid, 12, Color.Orange); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - var next = Mem.ReadU24(subObj + 9); - if ((next == 0) && ((mode & 1) != 0)) - { - DrawEccoOct(Xmid, Ymid, Mem.ReadS16(subObj + 0x3C), Color.Orange); - } - subObj = Mem.ReadU24(subObj + 9); - } - subObj = Mem.ReadU24(curObj + 5); - while (subObj != 0) - { - Xmid = Mem.ReadS32(subObj + 0x24); - Ymid = Mem.ReadS32(subObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(subObj + 0x54) + Mem.ReadS32(subObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(subObj + 0x58) + Mem.ReadS32(subObj + 0x60)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawEccoOct(Xmid, Ymid, 12, Color.Orange); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - var next = Mem.ReadU24(subObj + 5); - if ((next == 0) && ((mode & 2) != 0)) - { - DrawEccoOct(Xmid, Ymid, Mem.ReadS16(subObj + 0x3C), Color.Orange); - } - subObj = Mem.ReadU24(subObj + 5); - } - } - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - int Xtmp = Mem.ReadS32(curObj + 0x2C); - int Ytmp = Mem.ReadS32(curObj + 0x30); - int Xtmp2 = Mem.ReadS32(curObj + 0x34); - int Ytmp2 = Mem.ReadS32(curObj + 0x38); - Xpos = (Xtmp >> 16) - _camX; Xpos2 = (Xtmp2 >> 16) - _camX; - Ypos = (Ytmp >> 16) - _camY; Ypos2 = (Ytmp2 >> 16) - _camY; - Xvec = ((Mem.ReadS32(curObj + 0x24) + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Mem.ReadS32(curObj + 0x28) + +Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - if (mode < 7) - { - double overlap = 0; - DrawEccoOct(Xmid, Ymid, 0x5C, Mem.ReadByte(curObj + 0x7C) == 0 ? Color.Blue : Color.Gray); - DrawEccoOct(Xmid, Ymid, 0x5C, Color.Cyan, 0); - Xvec = (Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)); - Yvec = (Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)); - subObj = Mem.ReadU24(curObj + 0x69); - if (subObj != 0) - { - Xpos = Mem.ReadS32(subObj + 0x2C); - Ypos = Mem.ReadS32(subObj + 0x30); - Xpos2 = Mem.ReadS32(subObj + 0x34); - Ypos2 = Mem.ReadS32(subObj + 0x38); - while ((Xtmp > Xpos) && (Xtmp2 < Xpos2) && (Ytmp > Ypos) && (Ytmp2 < Ypos2) && ((Xvec != 0) || (Yvec != 0))) - { - Xtmp += Xvec; Xtmp2 += Xvec; - Ytmp += Yvec; Ytmp2 += Yvec; - } - overlap = Math.Max(Math.Max(Xpos - Xtmp, Xtmp2 - Xpos2), Math.Max(Ypos - Ytmp, Ytmp2 - Ypos2)) / 65536.0; - Xpos >>= 16; Xpos2 >>= 16; - Ypos >>= 16; Ypos2 >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, 0); - } - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, (overlap >= 6) ? Color.Orange : Color.White, (overlap >= 6) ? 63 : 0); - if (mode < 4) - { - Xmid = Mem.ReadS16(curObj + 0x4C) - _camX; - Ymid = Mem.ReadS16(curObj + 0x50) - _camY; - if ((mode & 1) == 0) DrawEccoOct(Xmid, Ymid - 0xAE, 32, Color.Orange); - if ((mode & 2) == 0) DrawEccoOct(Xmid, Ymid + 0xAE, 32, Color.Orange); - } - TickerText($"{mode}:{Mem.ReadByte(curObj + 0x7F)}:{Mem.ReadByte(curObj + 0x6D)}:{Mem.ReadByte(curObj + 0x7C)}", Color.Red); - } - else if (mode == 8) - { - DrawEccoOct(Xmid - 16, Ymid - 16, 12, Color.Red); - } - } - else if (type == 0xE1BA2) // Vortex Queen Boss - { - var vulnCount = Mem.ReadByte(curObj + 0x7F); - var state = Mem.ReadByte(curObj + 0x7C); - var stateCounter = Mem.ReadU16(curObj + 0x6E); - var mode = Mem.ReadU16(curObj + 0x64); - var modeCounter = Mem.ReadU16(curObj + 0x66); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x40); - Xvec = Xmid + Mem.ReadS32(curObj + 0x54); - Yvec = Ymid + Mem.ReadS32(curObj + 0x58); - Xvec >>= 16; Yvec >>= 16; - Xmid >>= 16; Ymid >>= 16; - Xvec -= _camX; Yvec -= _camY; - Xmid -= _camX; Ymid -= _camY; - if (mode < 5) - { - var octOff = (int)(80 * Math.Sqrt(2)) >> 1; - Point hexOff = Intersection(new Point(-80, 0), new Point(-octOff, -octOff), new Point(-80, -32), new Point(-octOff, -32)).Value; - Point[] roundedRect = { - new Point(Xmid - 80, Ymid), - new Point(Xmid + hexOff.X, Ymid - 32), - new Point(Xmid - hexOff.X, Ymid - 32), - new Point(Xmid + 80, Ymid), - new Point(Xmid - hexOff.X, Ymid + 32), - new Point(Xmid + hexOff.X, Ymid + 32) - }; - Gui.DrawPolygon(roundedRect, Color.Orange, Color.FromArgb(63, Color.Orange)); - } - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - TickerText($"{state:X2}:{stateCounter}:{mode}:{modeCounter}:{Mem.ReadByte(curObj + 0x70) & 0xF}", Color.Red); - var subObj = Mem.ReadU24(curObj + 0x5); - var tongueMode = mode; - mode = Mem.ReadByte(subObj + 0x15); - modeCounter = Mem.ReadU16(subObj + 0x6E); - Xmid = Mem.ReadS32(subObj + 0x24); - Ymid = Mem.ReadS32(subObj + 0x40); - Xvec = (Xmid + Mem.ReadS32(subObj + 0x5C) >> 16) - _camX; - Yvec = (Ymid + Mem.ReadS32(subObj + 0x60) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Ymid -= 32; Yvec -= 32; - var levelHeight = Mem.ReadS16(0xFFA7AC) - _camY; - switch (mode) - { - case 0: - DrawBox(Xmid - 32, Ymid - ((state == 5) ? 0x60 : 0x70), Xmid + 32, Ymid - 16, Color.Red); - break; - case 2: - Ypos = Mem.ReadS16(subObj + 0x50) - _camY; - Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); - DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); - break; - case 3: - modeCounter = Mem.ReadByte(subObj + 0x7C); - break; - case 5: - Point[] throatShape = - { - new Point(Xmid - 48, levelHeight), - new Point(Xmid - 48, Ymid + 60), - new Point(Xmid - 16, Ymid + 20), - new Point(Xmid + 16, Ymid + 20), - new Point(Xmid + 48, Ymid + 60), - new Point(Xmid + 48, levelHeight) - }; - Gui.DrawPolygon(throatShape, Color.Red, Color.FromArgb(63, Color.Red)); - DrawEccoOct(Xmid, Ymid, 24, Color.Red); - DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); - break; - case 6: - if ((state != 7) && (vulnCount == 0) && (tongueMode != 7)) - { - DrawEccoOct(Xmid, Ymid + 16, 64, Color.Blue); - } - if (tongueMode == 7) - { - uint subObj2 = Mem.ReadU24(0xFFCFCD); - while (subObj2 != 0) - { - if (Mem.ReadU16(subObj2 + 0x10) == 0xFF) - { - Xpos = Mem.ReadS16(subObj2 + 0x24) - _camX; - Ypos = Mem.ReadS16(subObj2 + 0x28) - _camY; - Xpos2 = ((Mem.ReadS32(subObj2 + 0x24) + Mem.ReadS32(subObj2 + 0x54)) >> 16) - _camX; - Ypos2 = ((Mem.ReadS32(subObj2 + 0x28) + Mem.ReadS32(subObj2 + 0x58)) >> 16) - _camY; - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - } - subObj2 = Mem.ReadU24(subObj2 + 1); - } - } - Ypos = Mem.ReadS16(subObj + 0x50) - _camY; - Gui.DrawLine(Xmid - 48, Ypos - 94, Xmid + 48, Ypos - 94, Color.Orange); - Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); - DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); - break; - default: - break; - } - if ((mode < 7) || ((mode == 7) && (Mem.ReadU24(0xFFCFC9) != 0))) - { - if (Mem.ReadByte(subObj + 0x70) == 0) - { - DrawEccoOct(Xmid, Ymid, 32, Color.Red); - DrawBox(Xmid - 48, Ymid + 32, Xmid + 48, levelHeight, Color.Red); - } - Ypos = Mem.ReadS16(subObj + 0x50) - _camY - 94; - Gui.DrawLine(Xmid - 48, Ypos, Xmid + 48, Ypos, Color.Orange); - DrawBoxMWH(Xmid, Ymid + 32, 1, 1, Color.Orange, 0); - } - if (Mem.ReadS32(subObj + 0xC) == 0xE17B4) - { - Point[] shapePoints = - { - new Point(Xmid - 48, levelHeight), - new Point(Xmid - 48, Ymid + 60), - new Point(Xmid - 16, Ymid + 20), - new Point(Xmid + 16, Ymid + 20), - new Point(Xmid + 48, Ymid + 60), - new Point(Xmid + 48, levelHeight) - }; - Gui.DrawPolygon(shapePoints, Color.Red, Color.FromArgb(63, Color.Red)); - DrawEccoOct(Xmid, Ymid, 24, Color.Red); - DrawEccoOct(Xmid, Ymid, 24, Color.White, 0); - } - Ypos = (Mem.ReadS16(subObj + 0x50) - _camY) - 264; - DrawBoxMWH(160 + _left, Ypos, 320, 12, (32 < stateCounter) && (stateCounter < 160) ? Color.Brown : Color.Gray); - if ((32 < stateCounter) && (stateCounter < 160)) - { - DrawBoxMWH(_left + 160, Ypos, 320, 12, Color.White, 0); - } - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - TickerText($"{mode:X2}:{modeCounter}:{HP}:{vulnCount}", Color.Red); - HP = 0; - } - else if (type == 0xA5BD2) // Telekinetic future dolphins - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); - DrawEccoOct(Xmid, Ymid, 4, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0x9F5B0) || (type == 0x9F4DC) || (type == 0x9F6A0)) // Falling rock, breaks barriers - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - if (type == 0x9F6A0) - { - int width = Mem.ReadS16(curObj + 0x44) << 1; - DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); - } - TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); - } - else if (type == 0xA3B18) - { - Xpos = Mem.ReadS32(curObj + 0x24); - Ypos = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(curObj + 0x44), Color.Yellow); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - } - else if (type == 0xA4018) - { - Xpos = Mem.ReadS32(curObj + 0x24); - Ypos = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; - Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, Mem.ReadS16(curObj + 0x44), Color.Gray); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - } - else if (type == 0xA091E) // Blue Whale - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xpos = Xmid; Ypos = Ymid; - Ymid -= 64; Yvec -= 64; - DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x50, Color.Red, 31); - DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x40, Color.Red, 31); - DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x30, Color.Red, 31); - DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x20, Color.Red, 31); - DrawEccoOct_scaled(Xmid, Ymid, 2, 0, 0x10, Color.Red, 31); - if (Mem.ReadByte(curObj + 0x7F) == 0) - { - Xpos += (Mem.ReadS16(curObj + 0x6E) == 0) ? -278 : 162; - Ypos += 44 - Mem.ReadS16(curObj + 0x48); - DrawEccoOct(Xpos, Ypos, 32, Color.Blue); - } - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - - } - else if (type == 0xE66D8) //Vortex Larva - { - uint subObj = Mem.ReadU24(curObj + 5); - while (subObj != 0) - { - Xpos = Mem.ReadS16(subObj + 0x1C); - Ypos = Mem.ReadS16(subObj + 0x20); - Xpos2 = Mem.ReadS16(subObj + 0x24); - Ypos2 = Mem.ReadS16(subObj + 0x28); - Xpos -= _camX; Ypos -= _camY; - Xpos2 -= _camX; Ypos2 -= _camY; - DrawEccoOct(Xpos, Ypos, 30, Color.White, 32); - DrawEccoOct(Xpos, Ypos, 30, Color.Yellow, 0); - DrawEccoOct(Xpos2, Ypos2, 30, Color.White, 32); - DrawEccoOct(Xpos2, Ypos2, 30, Color.Yellow, 0); - subObj = Mem.ReadU24(subObj + 5); - } - Xpos = Mem.ReadS32(curObj + 0x24); - Ypos = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xpos + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ypos + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xpos2 = Mem.ReadS16(curObj + 0x72) - _camX; - Ypos2 = Mem.ReadS16(curObj + 0x76) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; Ypos -= _camY; - DrawEccoOct(Xpos, Ypos, 0xB0, Color.Yellow); - DrawEccoOct(Xpos, Ypos, 0xB0, Color.Red, 0); - DrawEccoOct(Xpos, Ypos, 0x70, Color.Red); - DrawEccoOct(Xpos, Ypos, 0x38, Color.White); - DrawEccoOct(Xpos, Ypos, 0x38, Color.Red, 0); - DrawEccoOct(Xpos, Ypos, 48, Color.Blue, ((Mem.ReadByte(curObj + 0x7B) > 2) && (Mem.ReadByte(curObj + 0x14) != 0)) ? 63 : 0); - DrawEccoOct(Xpos2, Ypos2, 32, Color.Orange); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - TickerText($"{Mem.ReadByte(curObj + 0x14):X2}:{Mem.ReadByte(curObj + 0x7B):X2}:{Mem.ReadS16(curObj + 0x6E):D2}", Color.Red); - TickerText($"{ Mem.ReadByte(curObj + 0x7C):X2}:{Mem.ReadS16(curObj + 0x18):D3}", Color.Red); - TickerText($"{(Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C))/65536.0:0.######}:{(Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) / 65536.0:0.######}", Color.Red); - - } - else if (type == 0x9CE3A) //Remnant Stars - { - flags = Mem.ReadU16(curObj + 0x10); - uint subObj = Mem.ReadU24(curObj + 0x5); - uint anim = Mem.ReadU16(curObj + 0x6C); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - if ((anim <= 7) && (subObj == 0xFFA9D4)) - { - DrawEccoRhomb(Xmid, Ymid, 96, Color.Red); - PutText($"{((7 - anim) * 4) - ((Mem.ReadByte(0xFFA7C9) & 3) - 4)}", Xmid, Ymid + 4, 1, 1, -1, -1, Color.Blue, Color.Red); - - } - } - else if (type == 0xA997C) // Vortex Soldier - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = (Xmid + Mem.ReadS32(curObj + 0x54) >> 16) - _camX; - Yvec = (Ymid + Mem.ReadS32(curObj + 0x58) >> 16) - _camY; - Xvec += Mem.ReadS16(curObj + 0x64); - Yvec += Mem.ReadS16(curObj + 0x66); - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - if (Mem.ReadByte(curObj + 0x7A) == 0) - { - DrawRectRhombusIntersection(new Point(Xmid, Ymid + 6), new Point(Xmid, Ymid), 50, 44, 64, Color.Red); - } - DrawRectRhombusIntersection(new Point(Xmid, Ymid - 25), new Point(Xmid, Ymid), 38, 47, 64, Color.Red); - DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue, 16); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xA6C4A) || (type == 0xC43D4)) // Barrier Glyphs - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - var subType = Mem.ReadByte(curObj + 0x13); - if ((Mem.ReadU8(curObj + 0x7A) == 0) && (Mem.ReadU8(0xFFA7B5) != 0) - && ((type != 0xA6C4A) || (subType == 0x14) || (subType == 0x97))) - { - DrawEccoOct(Xmid, Ymid, 70, Color.Red); - } - DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue); - DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.PowderBlue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xB4F46) || (type == 0xB4E1C) || (type == 0xB4C18) || (type == 0xB4ACC) || (type == 0xB4B72)) // Guiding Orca/Dolphin - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - int Xdst = Mem.ReadS16(curObj + 0x64); - Xdst <<= 7; - Xdst = Xdst + 0x40 - _camX; - int Ydst = Mem.ReadS16(curObj + 0x66); - Ydst <<= 7; - Ydst = Ydst + 0x40 - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - Gui.DrawLine(Xmid, Ymid, Xdst, Ydst, Color.Orange); - DrawBoxMWH(Xdst, Ydst, 64, 64, Color.Orange); - TickerText($"{Mem.ReadS16(curObj + 0x24)}:{Mem.ReadS16(curObj + 0x28)}:{Mem.ReadByte(curObj + 0x7D)}:{Mem.ReadByte(curObj + 0x7A)}", Color.Lime); - TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); - TickerText($"{Mem.ReadS32(curObj + 0x72) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x76) / 65536.0:0.######}", Color.Lime); - } - else if (type == 0xB5938) // Lost Orca - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - //DrawBoxMWH(Xmid, Ymid, 64, 32, Color.Lime); - if (Mem.ReadU16(curObj + 0x6E) == 0) - { - if (Mem.ReadByte(curObj + 0x7D) == 0) - { - DrawBox(Xmid + 8, Ymid - 32, Xmid + 64, Ymid + 32, Color.Red); - } - else - { - DrawBox(Xmid - 64, Ymid - 32, Xmid - 8, Ymid + 32, Color.Red); - } - } - Gui.DrawLine(Xpos - 80, Ymid, Xpos + 80, Ymid, Color.Green); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xB552A) || (type == 0xB5C42) || (type == 0xB5AFE)) // Following Orca, Returning Orca, & Idling Orca - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xB624A) // Orca Mother - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - int height = Mem.ReadS16(curObj + 0x48) + 32; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 80, 32, Color.Red, 31); - DrawBoxMWH(Xmid, Ymid, Mem.ReadS16(curObj + 0x44), Mem.ReadS16(curObj + 0x48), Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - if (Mem.ReadS32(0xFFAB7E) != 0) - { - DrawEccoOct(Xmid, Ymid, 0x50, Color.Red, 31); - } - } - else if (type == 0xC047E) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - var width = 2; - var height = 2; - if (Mem.ReadByte(curObj + 0x15) == 0) - { - width = Mem.ReadS16(curObj + 0x44); - height = Mem.ReadS16(curObj + 0x48); - } - DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); - } - else if (type == 0xC056E) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - var width = Mem.ReadS16(curObj + 0x44); - var height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Lime); - } - else if (type == 0xC4208) // Broken Glyph Base - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - var width = Mem.ReadS16(curObj + 0x44); - var height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.PowderBlue); - if (Mem.ReadByte(curObj + 0x15) == 0) - { - DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 80, 80, 120, Color.Orange); - } - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xAC242) // Broken Glyph Top repairing - { - uint subObj = Mem.ReadU24(curObj + 0x5); - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - Xpos = Mem.ReadS16(subObj + 0x24) - _camX; - Ypos = Mem.ReadS16(subObj + 0x28) - _camY; - var width = Mem.ReadS16(curObj + 0x44); - var height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Gray); - Point[] rhombPoints = - { - new Point(Xpos - 3, Ypos), - new Point(Xpos, Ypos - 3), - new Point(Xpos + 3, Ypos), - new Point(Xpos, Ypos + 3) - }; - Gui.DrawPolygon(rhombPoints, Color.Orange, Color.FromArgb(63, Color.Orange)); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); - } - else if (type == 0xBE9C8) // Broken Glyph Top free - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Lime); Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xD9C0E) || (type == 0xDA9EA)) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBoxMWH(Xmid, Ymid, 0xA0, 0x70, Color.Red); - } - else if ((type == 0xBF204) || (type == 0xDA2C0)) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xAF9CC) // Mirror Dolphin - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xpos = Mem.ReadS16(curObj + 0x1C) - _camX + (Mem.ReadByte(curObj + 0x15) == 0 ? 27 : -27); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54) + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58) + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - var width = Mem.ReadS16(curObj + 0x44); - var height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue, 31); - if (Mem.ReadByte(curObj + 0x13) != 0xAC) - { - DrawBoxMWH(Xmid, Ymid, 96, 96, Color.Orange); - } - Gui.DrawLine(Xpos, 0, Xpos, 448, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xAF43E) // Vortex Lightning Trap - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - if (Mem.ReadByte(curObj + 0x15) != 0) - { - if (Mem.ReadS16(0xFFAA12) != 0) - { - Ymid -= 8; - } - DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Red); - PutText(Mem.ReadByte(curObj + 0x15).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); - } - else - { - DrawBoxMWH(Xmid, Ymid, 92, 16, Color.Gray); - PutText(Mem.ReadByte(curObj + 0x7F).ToString(), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); - } - } - else if (type == 0xA6E24) // Barrier Glyph Forcefield - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = Mem.ReadS32(0xFFAA1A) - Xmid; - Yvec = Mem.ReadS32(0xFFAA1E) - Ymid; - var div = Math.Abs(Xvec) + Math.Abs(Yvec); - Xvec /= div; Yvec /= div; - Xvec += Xmid; Yvec += Ymid; - Xmid >>= 16; Ymid >>= 16; - Xvec >>= 16; Yvec >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xvec -= _camX; Yvec -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xC4A44) || (type == 0xAA32C)) // Pulsar power-up and Vortex bullet-spawner - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue, 16); - } - else if (type == 0xC2F00) // Sky bubbles - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - var mode = Mem.ReadByte(curObj + 0x15); - switch (mode) - { - case 0: - DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 70, 70, 105, Color.Gray); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - break; - case 1: - DrawRectRhombusIntersection(new Point(Xmid, Ymid), new Point(Xmid, Ymid), 70, 70, 105, Color.Red); - break; - case 2: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); - break; - default: - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Gray); - break; - } - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0x9FA7E) //Air refiller/drainer - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Lime)); - } - else if (type == 0xBFC14) //Pushable fish - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - TickerText($"{Mem.ReadS32(curObj + 0x54) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x58) / 65536.0:0.######}", Color.Orange); - - } - else if ((type == 0xBE97C) //Slowing Kelp //Default Bounds nose-responsive - || (type == 0xACDAE)) //Metasphere - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xACB42) // Turtle - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - var mode = Mem.ReadByte(curObj + 0x15); - switch (mode) - { - case 0: - case 1: - case 2: - case 3: - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x4C)) >> 16) - _camX; - break; - case 4: - case 5: - case 6: - case 7: - Xvec = ((Xmid - Mem.ReadS32(curObj + 0x4C)) >> 16) - _camX; - break; - default: - Xvec = (Xmid >> 16) - _camX; - break; - } - Yvec = Ymid; - Xmid >>= 16; Xmid -= _camX; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - int width = Mem.ReadS16(curObj + 0x44) << 1; - DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); - TickerText($"{Mem.ReadS32(curObj + 0x4C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x50) / 65536.0:0.######}", Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xACA7E) // Retracting Turtle - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + (Mem.ReadS32(curObj + 0x4C) >> 1)) >> 16) - _camX; - Yvec = ((Ymid + (Mem.ReadS32(curObj + 0x50) >> 1)) >> 16) - _camY; - Xmid >>= 16; Xmid -= _camX; - Ymid >>= 16; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - int width = Mem.ReadS16(curObj + 0x44) << 1; - DrawBox(Xpos - width, Ypos - (width << 2), Xpos2 + width, Ypos2, Color.Lime); - TickerText($"{(Mem.ReadS32(curObj + 0x4C) >> 1) / 65536.0:0.######}:{(Mem.ReadS32(curObj + 0x50) >> 1) / 65536.0:0.######}", Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xB5134) || (type == 0xA7E0C) //Default Bounds sonar-responsive - || (type == 0xAF868) || (type == 0xAF960) || (type == 0xD8E5C) || (type == 0xAA5C6)) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if ((type == 0xACCB4) || (type == 0xACD7E) //Default Baunds non-responsive - || (type == 0xD8D96) || (type == 0xA955E) || (type == 0xA92E4) || (type == 0xC05DC) - || (type == 0xC2684)) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Gray); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0x9DE86) // Star Wreath - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xpos = Mem.ReadS32(curObj + 0x1C); - Ypos = Mem.ReadS32(curObj + 0x20); - Xpos2 = ((Xpos + Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Ypos2 = ((Ypos + Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; Ypos -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - DrawBoxMWH(Xpos, Ypos, 1, 1, (Mem.ReadByte(curObj + 0x7F) == 0) ? Color.Blue : Color.Black, 0); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - if (Mem.ReadByte(curObj + 0x12) % 7 == 0) - { - TickerText($"{Mem.ReadS32(curObj + 0x5C) / 65536.0:0.######}:{Mem.ReadS32(curObj + 0x60) / 65536.0:0.######}:{Mem.ReadByte(curObj + 0x7F)}", Color.Lime); - } - } - else if ((type == 0x9D774) || (type == 0x9DA26)) // Fish - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 0x14, 0x14, Color.Lime); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xAD87C) // Enemy dolphins in metamorph levels - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Mem.ReadS16(curObj + 0x1C) - _camX, Mem.ReadS16(curObj + 0x20) - _camY, 1024, 1024, Color.Orange, 0); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC6128) // Drone attacking dolphin - { - Xmid = Mem.ReadS16(curObj + 0x4C) - _camX; - Ymid = Mem.ReadS16(curObj + 0x50) - _camY; - DrawEccoOct(Xmid, Ymid, 360, Color.Red, 0); - } - else if (type == 0xC605A) // Drone attacking dolphin sonar - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camY; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBox(Xmid, Ymid - 1, Xmid + 32, Ymid + 1, Color.Orange); - } - else if (type == 0xB1BE0) // Globe - { - int mode = Mem.ReadS8(curObj + 0x15); - if (mode == 1) - { - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime, 0); - Gui.DrawLine(Xpos, Ypos2, Xpos2, Ypos, Color.Lime); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xB1A10) // Approaching globes - { - Xmid = Mem.ReadS16(0xFFAA1A) - _camX; - Ymid = Mem.ReadS16(0xFFAA1E) - _camY; - DrawEccoOct(Xmid - 56, Ymid, 8, Color.Orange); - DrawEccoOct(Xmid + 56, Ymid, 8, Color.Orange); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xpos = Mem.ReadS32(curObj + 0x4C); - Ypos = Mem.ReadS32(curObj + 0x50); - Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xpos2 = ((Xpos + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Ypos2 = ((Ypos + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xpos >>= 16; Ypos >>= 16; - Xpos -= _camX; Ypos -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xpos2, Ypos2, Color.Orange); - } - else if (type == 0xB1920) // Orbiting globes - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xpos = Mem.ReadS16(curObj + 0x4C) - _camX; - Ypos = Mem.ReadS16(curObj + 0x50) - _camY; - Xvec = ((Xmid - Mem.ReadS32(curObj + 0x5C)) >> 16) - _camX; - Yvec = ((Ymid - Mem.ReadS32(curObj + 0x60)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - DrawBoxMWH(Xpos, Ypos, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xpos, Ypos, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC28A0) // Control point in Four Islands/Dolphin that gives Rock-breaking song - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Mem.ReadByte(curObj + 0x15) == 0 ? Color.Orange : Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - // Crystal Springs merging glyphs - else if (type == 0xC651E) // Bound glyph - { - Xpos = Mem.ReadS16(curObj + 0x1C) - _camX; - Ypos = Mem.ReadS16(curObj + 0x20) - _camY; - DrawEccoRhomb(Xpos, Ypos, 4 << 4, Color.Orange); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC67E4) // Freed glyph - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Blue); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC6970) // Pulled glyph - { - uint subObj = Mem.ReadU24(curObj + 5); - Xvec = Mem.ReadS32(subObj + 0x54); - Yvec = Mem.ReadS32(subObj + 0x58); - for (i = 1; i < Mem.ReadByte(curObj + 0x7F); i++) - { - Xvec ^= Yvec; - Yvec ^= Xvec; - Xvec ^= Yvec; - Xvec = 0 - Xvec; - } - Xpos = (Xvec + Mem.ReadS32(subObj + 0x1C) >> 16) - _camX; - Ypos = (Yvec + Mem.ReadS32(subObj + 0x20) >> 16) - _camY; - DrawEccoRhomb(Xpos, Ypos, 3, Color.Orange); - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - } - else if (type == 0xC6BA8) // Delivery Point - { - Xvec = Mem.ReadS32(curObj + 0x54); - Yvec = Mem.ReadS32(curObj + 0x58); - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - for (i = 0; i < 4; i++) - { - Xpos = (Xvec + Mem.ReadS32(curObj + 0x1C) >> 16) - _camX; - Ypos = (Yvec + Mem.ReadS32(curObj + 0x20) >> 16) - _camY; - Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); - Xvec ^= Yvec; - Yvec ^= Xvec; - Xvec ^= Yvec; - Xvec = 0 - Xvec; - } - } - else if (type == 0xC6A6C) // Delivered glyph - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC6F82) // Full delivery point - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawEccoOct(Xmid, Ymid, 3, Color.Orange); - } - else if (type == 0xC6A9E) // Merging glyph - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid - Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid - Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xC7052) { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS16(curObj + 0x24); - Ymid = Mem.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - uint dropSpeed = Mem.ReadU8(curObj + 0x16); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xmid, Ymid + (int)(dropSpeed), Color.Orange); - } - else if ((type == 0xD8B7C) || (type == 0xD89EA) || (type == 0x9E3AA) || (type == 0x9E5A8) // GFX particles don't need displayed. - || (type == 0x9B5D8) || (type == 0x9E2A6) || (type == 0xACD1E) || (type == 0xD9678) - || (type == 0xD9A3C) || (type == 0xD9240) || (type == 0x9E1DE) || (type == 0xDF86A) - || (type == 0xB159A) || (type == 0xDA898) || (type == 0xDA720) || (type == 0xD9FDC) - || (type == 0xC0D4E) || (type == 0xC0D38) || (type == 0xDCDAC) || (type == 0xC0B42) - || (type == 0xE3CD2) || (type == 0xE385E) || (type == 0xC20E8) || (type == 0xC22A6) - || (type == 0xC31B4) || (type == 0xA9EF0) || (type == 0xA9D90) || (type == 0xC6304) - || (type == 0xC26E4) || (type == 0xAEE68) || (type == 0xD9B2A) || (type == 0xD95AE) - || (type == 0)) - { - // This space intentionally left blank - } - else if ((type == 0xC152C) || (type == 0xA75E8) //Objects with default bounds confirmed - || (type == 0x9D076) || (type == 0xA7092) || (type == 0xC02EA) || (type == 0xA5378) - || (type == 0xACA7E) || (type == 0x9D28C) || (type == 0xA2D42) || (type == 0xA975E) - || (type == 0xBE9C8) || (type == 0xBFDA4) || (type == 0xAC736) || (type == 0xB716E) - || (type == 0xB1BE0) || (type == 0xB1A10) || (type == 0x9E546) || (type == 0xC2CB8) - || (type == 0xA0F04) || (type == 0xA6ACA) || (type == 0xA35A6) || (type == 0xAA12E) - || (type == 0xC651E) || (type == 0x9CC06) || (type == 0xA9202) || (type == 0xA6FDE) - || (type == 0xA6F62) || (type == 0xA745C) || (type == 0xC3EF0) || (type == 0xC3F90) - || (type == 0xC3FFC) || (type == 0xC3DB8) || (type == 0xAC766) || (type == 0xC5F66) - || (type == 0xA306E) || (type == 0xB0C7E) || (type == 0xB17F2) || (type == 0xB0CDC) - || (type == 0xC2106) || (type == 0xC208C) || (type == 0xC1EBA) || (type == 0xC251C) - || (type == 0xC32C8) || (type == 0xAB5E6) || (type == 0xAC796) || (type == 0xAC9F2) - || (type == 0xA538A)) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(255, 0, 127)); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - if (type != 0xA975E) - { - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - if (HP > 2) - { - PutText($"{HP - 1}", Xmid, Ymid, 1, 1, -1, -9, Color.Blue, Color.Red); - } - } - else // Default bounds - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - PutText(type.ToString("X5"), Xmid, Ymid + 8, 1, 9, -1, -1, Color.Blue, Color.Red); - } - break; - } - case Modes.Ecco1: - type = Mem.ReadU32(curObj + 0x6); - Xpos = Mem.ReadS16(curObj + 0x17); - Xpos2 = Mem.ReadS16(curObj + 0x1F); - Ypos = Mem.ReadS16(curObj + 0x1B); - Ypos2 = Mem.ReadS16(curObj + 0x23); - Xmid = Mem.ReadS16(curObj + 0x0F); - Ymid = Mem.ReadS16(curObj + 0x13); - Xpos >>= 2; - Xpos2 >>= 2; - Ypos >>= 2; - Ypos2 >>= 2; - Xmid >>= 2; - Ymid >>= 2; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Lime); - PutText(type.ToString("X8"), Xmid, Ymid, 1, 1, -1, -1, Color.Blue, Color.Red); - break; - } - curObj = Mem.ReadU24(curObj+1); - } - //events - curObj = Mem.ReadU24(0xFFCFB5); - while (curObj != 0) - { - type = Mem.ReadU32(curObj + 0xC); - if ((type == 0) // Null object - || (type == 0x9C1FA) || (type == 0x9C6D0) // Skytubes BG Image manager - || (type == 0x9ED72) || (type == 0xA57F2) // And Miscellaneous GFX particles - || (type == 0xC3A42) || (type == 0xB33D8) // And Cutscene controller - || (type == 0xB308A) || (type == 0xA1676) || (type == 0xB6822) || (type == 0xD12E2)) { } - else if ((type == 0xA44EE) || (type == 0xD120C)) - { - Xmid = Mem.ReadS16(curObj + 0x1C) - _camX; - Ymid = Mem.ReadS16(curObj + 0x20) - _camY; - DrawEccoOct(Xmid, Ymid, 0x20, Color.Red); - } - else if (type == 0x9F0D0) // Water Current - { - int Xvec = Mem.ReadS32(curObj + 0x54); - int Yvec = Mem.ReadS32(curObj + 0x58); - if ((Xvec != 0) || (Yvec != 0)) - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - Xvec += Xmid; Yvec += Ymid; - Xmid >>= 16; Ymid >>= 16; - Xvec >>= 16; Yvec >>= 16; - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - Xvec -= _camX; Yvec -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63, Color.Red)); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - } - else if (type == 0xDEF94) - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawEccoOct(Xmid, Ymid, 0x18, Color.Cyan); - } - else if (type == 0xA6584) // Eagle - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawEccoOct(Xmid, Ymid, 0x10, Color.Red); - } - else if ((type == 0x9BA8A) // Autoscroller controller - || (type == 0xE27D4) || (type == 0xE270E) || (type == 0xE26C2)) - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - var Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - var Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Orange, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0x9B948) // Autoscroller waypoint - { - Xmid = Mem.ReadS32(curObj + 0x24); - Ymid = Mem.ReadS32(curObj + 0x28); - var Xvec = ((Xmid + Mem.ReadS32(curObj + 0x54)) >> 16) - _camX; - var Yvec = ((Ymid + Mem.ReadS32(curObj + 0x58)) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 8, 8, Color.Orange); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - else if (type == 0xA5448) // Bomb spawner - { - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - PutText($"{Mem.ReadU16(curObj + 0x6E)}", Xmid, Ymid, 1, 1, -1, -1, Color.White, Color.Blue); - } - else if ((type == 0xA529C) || (type == 0xA5236) || (type == 0xA51E6)) // Explosion - { - uint subObj = Mem.ReadU24(curObj + 5); - if (subObj != 0) - { - Xpos = Mem.ReadS16(subObj + 0x1C) - _camX; - Ypos = Mem.ReadS16(subObj + 0x28) - _camY; - int Width = Mem.ReadS16(subObj + 0x24) - Xpos - _camX; - DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); - } - subObj = Mem.ReadU24(curObj + 9); - if (subObj != 0) - { - Xpos = Mem.ReadS16(subObj + 0x1C) - _camX; - Ypos = Mem.ReadS16(subObj + 0x28) - _camY; - int Width = Mem.ReadS16(subObj + 0x24) - Xpos - _camX; - DrawBoxMWH(Xpos, Ypos, Width, 16, Color.Red); - } - } - else if (type == 0x9B5D8) - { - var subtype = Mem.ReadByte(curObj + 0x13); - int width = 0; - int height = 0; - switch (subtype) - { - case 48: - case 49: - case 126: - case 145: - case 146: - case 213: - PutText($"{type:X5}:{subtype}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); - PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); - break; - case 59: - case 87: - case 181: - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - width = Mem.ReadS16(curObj + 0x44); - height = Mem.ReadS16(curObj + 0x48); - DrawEccoOct(Xmid, Ymid, (width + height) >> 1, Color.Lime); - break; - case 71: - case 72: - case 158: - case 159: - case 165: - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red); - break; - case 82: - case 83: - case 84: - case 85: - case 86: - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - width = Mem.ReadS16(curObj + 0x44); - height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Red); - break; - case 210: - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - width = Mem.ReadS16(curObj + 0x44); - height = Mem.ReadS16(curObj + 0x48); - DrawBoxMWH(Xmid, Ymid, width, height, Color.Blue); - break; - case 107: - Xmid = (Mem.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; - Ymid = (Mem.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; - Xpos = (Mem.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; - Ypos = (Mem.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; - DrawBoxMWH(Xmid, Ymid, 64, 64, Color.Orange, 0); - DrawBoxMWH(Xpos, Ypos, 64, 64, Color.Orange, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); - break; - case 110: //Gravity conrol points - case 179: - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.FromArgb(63,Mem.ReadByte(curObj + 0x15) == 0 ? Color.Gray : Color.Red)); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); - int dir = Mem.ReadS8(curObj + 0x71) & 7; - int[] xtable = { 7, 4, -3, -10, -14, -11, -3, 4}; - int[] ytable = { 11, 4, 7, 4, -3, -11, -14, -11}; - Xmid = Mem.ReadS16(curObj + 0x24) - _camX; - Ymid = Mem.ReadS16(curObj + 0x28) - _camY; - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawImage(".\\dll\\gravitometer_bg.png", Xmid - 15, Ymid - 15); - Gui.DrawImage(".\\dll\\gravitometer_fg.png", Xmid + xtable[dir], Ymid + ytable[dir]); - break; - case 176: - Xmid = (Mem.ReadS16(curObj + 0x18) << 7) - _camX + 0x40; - Ymid = (Mem.ReadS16(curObj + 0x1A) << 7) - _camY + 0x40; - Xpos = (Mem.ReadS16(curObj + 0x64) << 7) - _camX + 0x40; - Ypos = (Mem.ReadS16(curObj + 0x66) << 7) - _camY + 0x40; - DrawEccoOct(Xmid, Ymid, 32, Color.Orange, 0); - DrawEccoOct(Xpos, Ypos, 32, Color.Orange, 0); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue, 0); - Gui.DrawLine(Xmid, Ymid, Xpos, Ypos, Color.Orange); - break; - case 194: // Kill plane - Xpos = Mem.ReadS16(curObj + 0x2C) - _camX; - Xpos2 = Mem.ReadS16(curObj + 0x34) - _camX; - Ypos = Mem.ReadS16(curObj + 0x30) - _camY; - Ypos2 = Mem.ReadS16(curObj + 0x38) - _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Black, 127); - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Red, 0); - break; - default: - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2 = Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2 = Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS16(curObj + 0x24); - Ymid = Mem.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); - PutText($"{type:X5}:{subtype}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); - PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); - break; - } - } - else - { - Xpos = Mem.ReadS16(curObj + 0x2C); - Xpos2= Mem.ReadS16(curObj + 0x34); - Ypos = Mem.ReadS16(curObj + 0x30); - Ypos2= Mem.ReadS16(curObj + 0x38); - Xmid = Mem.ReadS16(curObj + 0x24); - Ymid = Mem.ReadS16(curObj + 0x28); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.Cyan); - PutText($"{type:X5}:{Mem.ReadByte(curObj + 0x13)}", Xmid, Ymid - 4, 1, 1, -1, -9, Color.White, Color.Blue); - PutText(curObj.ToString("X6"), Xmid, Ymid + 4, 1, 9, -1, -1, Color.White, Color.Blue); - } - curObj = Mem.ReadU24(curObj+1); - } - //Ecco head - Xpos = Mem.ReadS16(0xFFA8F8); - Xpos2 = Mem.ReadS16(0xFFA900); - Ypos = Mem.ReadS16(0xFFA8FC); - Ypos2 = Mem.ReadS16(0xFFA904); - Xmid = Mem.ReadS16(0xFFA8F0); - Ymid = Mem.ReadS16(0xFFA8F4); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); - //Ecco tail - Xpos = Mem.ReadS16(0xFFA978); - Xpos2 = Mem.ReadS16(0xFFA980); - Ypos = Mem.ReadS16(0xFFA97C); - Ypos2 = Mem.ReadS16(0xFFA984); - Xmid = Mem.ReadS16(0xFFA970); - Ymid = Mem.ReadS16(0xFFA974); - Xpos -= _camX; Xpos2 -= _camX; - Ypos -= _camY; Ypos2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - DrawBox(Xpos, Ypos, Xpos2, Ypos2, Color.PowderBlue); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.PowderBlue, 0); - //Ecco body - Xpos = Mem.ReadS32(0xFFAA22); - Ypos = Mem.ReadS32(0xFFAA26); - Xpos2 = Mem.ReadS32(0xFFAA2A); - Ypos2 = Mem.ReadS32(0xFFAA2E); - Xmid = Mem.ReadS16(0xFFAA1A); - Ymid = Mem.ReadS16(0xFFAA1E); - int Xvel = Mem.ReadS32(0xFFAA36); - if (Mem.ReadU32(0xFFA9D6) > 7) Xvel += Mem.ReadS32(0xFFA9D6); - if (Mem.ReadU32(0xFFAA3E) > 7) Xvel += Mem.ReadS32(0xFFAA3E); - int Yvel = Mem.ReadS32(0xFFAA3A); - if (Mem.ReadU32(0xFFA9DA) > 7) Yvel += Mem.ReadS32(0xFFA9DA); - if (Mem.ReadU32(0xFFAA42) > 7) Yvel += Mem.ReadS32(0xFFAA42); - int XV = ((Xpos + Xvel) >> 16) - _camX; - int YV = ((Ypos + Yvel) >> 16) - _camY; - int XV2 = ((Xpos2 + Xvel) >> 16) - _camX; - int YV2 = ((Ypos2 + Yvel) >> 16) - _camY; - X = Xpos >> 16; - X2 = Xpos2 >> 16; - Y = Ypos >> 16; - Y2 = Ypos2 >> 16; - X -= _camX; X2 -= _camX; - Y -= _camY; Y2 -= _camY; - Xmid -= _camX; Ymid -= _camY; - int X3 = (Xmid + X) >> 1; - int X4 = (Xmid + X2) >> 1; - int Y3 = (Ymid + Y) >> 1; - int Y4 = (Ymid + Y2) >> 1; - Gui.DrawLine(X, Y, Xmid, Ymid, Color.Green); - Gui.DrawLine(Xmid, Ymid, X2, Y2, Color.Green); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Red); - DrawBoxMWH(X, Y, 1, 1, Color.Lime); - DrawBoxMWH(X2, Y2, 1, 1, Color.Blue); - DrawBoxMWH(X3, Y3, 1, 1, Color.Yellow); - DrawBoxMWH(X4, Y4, 1, 1, Color.Yellow); - Gui.DrawLine(X, Y, XV, YV, Color.Orange); - Gui.DrawLine(X2, Y2, XV2, YV2, Color.Orange); - // sonar - if (Mem.ReadU8(0xFFAB77) != 0) - { - Xmid = Mem.ReadS32(0xFFA9EC); - Ymid = Mem.ReadS32(0xFFA9F0); - int Xvec = ((Mem.ReadS32(0xFFAA04) + Xmid) >> 16) - _camX; - int Yvec = ((Mem.ReadS32(0xFFAA08) + Ymid) >> 16) - _camY; - Xmid >>= 16; - Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - Width2 = Mem.ReadS16(0xFFA9FC); - Height2 = Mem.ReadS16(0xFFAA00); - color = ((Mem.ReadU8(0xFFAA0C) != 0) ? Color.FromArgb(255, 0, 127) : Color.FromArgb(0, 0, 255)); - DrawBoxMWH(Xmid, Ymid, Width2, Height2, color); - DrawBoxMWH(Xmid, Ymid, 1, 1, color, 0); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - //Pulsar - curObj = Mem.ReadU24(0xFFCFD1); - if ((curObj != 0) && ((Mem.ReadU32(curObj + 0xC) == 0xC9222) || (Mem.ReadU32(curObj + 0xC) == 0xC9456))) - { - curObj += 0x26; - for (int l = 0; l < 4; l++) - { - if (Mem.ReadU16(curObj + 0x12) != 0) - { - Xmid = Mem.ReadS32(curObj); - Ymid = Mem.ReadS32(curObj + 4); - int Xvec = (Xmid + Mem.ReadS32(curObj + 8) >> 16) - _camX; - int Yvec = (Ymid + Mem.ReadS32(curObj + 0xC) >> 16) - _camY; - Xmid >>= 16; Ymid >>= 16; - Xmid -= _camX; Ymid -= _camY; - DrawBoxMWH(Xmid, Ymid, 0x30, 0x30, Color.Red); - DrawBoxMWH(Xmid, Ymid, 1, 1, Color.Blue); - Gui.DrawLine(Xmid, Ymid, Xvec, Yvec, Color.Orange); - } - curObj += 0x14; - } - } - - //Water Level - int waterLevel = Mem.ReadS16(0xFFA7B2); - Gui.DrawLine(0, waterLevel - _camY, _left + 320 + _right, waterLevel - _camY, Color.Aqua); - - } - - void EccoAutofire(bool on) - { - //Modif N - ECCO HACK - make caps lock (weirdly) autofire player 1's C key - uint charge; - uint mode = Mem.ReadU8(0xFFA555); - int frameCount = Emu.FrameCount(); - int lagCount = Emu.LagCount(); - Joy.Set("Start", on, 1); - switch (mode) - { - case 0x00: - if (on) - { - if (Mem.ReadU16(0xFFF342) == 0xFFFD) - Joy.Set("C", true, 1); - else - Joy.Set("C", false, 1); - } - break; - case 0xE6: - if (Mem.ReadU16(0xFFD5E8) == 0x00000002) { - Dictionary buttons = new Dictionary(); - buttons["B"] = buttons["C"] = true; - Joy.Set(buttons, 1); - } - else - { - Dictionary buttons = new Dictionary(); - buttons["B"] = buttons["C"] = false; - Joy.Set(buttons, 1); - } - break; - case 0xF6: - charge = Mem.ReadU8(0xFFB19B); - if (on) - { - if ((charge <= 1) && ((Mem.ReadU8(0xFFB1A6) == 0) || (Mem.ReadU8(0xFFB1A9) != 0))) - Joy.Set("B", true, 1); - else if (charge > 1) - Joy.Set("B", false, 1); - Joy.Set("C", (Mem.ReadU16(0xFFA7C8) % 2) == 0, 1); - } - break; - case 0x20: - case 0x28: - case 0xAC: - if (on) - { - if ((Mem.ReadU8(0xFFAB72) & 3) == 0) - Joy.Set("C", (Mem.ReadS8(0xFFAA6E) < 11), 1); - } - break; - default: - break; - } - } - public override void Init(IApiContainer api) - { - base.Init(api); - Mem.SetBigEndian(); - string gameName = GI.GetRomName(); - if ((gameName == "ECCO - The Tides of Time (J) [!]") || - (gameName == "ECCO - The Tides of Time (U) [!]") || - (gameName == "ECCO - The Tides of Time (E) [!]")) - { - _mode = Modes.Ecco2; - _camXAddr = 0xFFAD9C; - _camYAddr = 0xFFAD9E; - _top = _bottom = 112; - _left = _right = 160; - ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); - } - else if ((gameName == "ECCO The Dolphin (J) [!]") || - (gameName == "ECCO The Dolphin (UE) [!]")) - - { - _mode = Modes.Ecco1; - _camXAddr = 0xFFB836; - _camYAddr = 0xFFB834; - _top = _bottom = 112; - _left = _right = 160; - ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); - } - else - { - _mode = Modes.disabled; - Running = false; - } - } - private Color BackdropColor() - { - uint color = Mem.ReadU16(0, "CRAM"); - int r = (int)(( color & 0x7) * 0x22); - int g = (int)(((color >> 3) & 0x7) * 0x22); - int b = (int)(((color >> 6) & 0x7) * 0x22); - return Color.FromArgb(r, g, b); - } - public override void PreFrameCallback() - { - Gui.ClearText(); - if (_mode != Modes.disabled) - { - _camX = Mem.ReadS16(_camXAddr) - _left; - _camY = Mem.ReadS16(_camYAddr) - _top; - EccoAutofire(Joy.Get(1)["Start"]); - if (_dumpMap == 0) - { - Color bg = BackdropColor(); - Gui.DrawRectangle(0, 0, _left + 320 + _right, _top, bg, bg); - Gui.DrawRectangle(0, 0, _left, _top + 224 + _bottom, bg, bg); - Gui.DrawRectangle(_left + 320, 0, _left + 320 + _right, _top + 224 + _bottom, bg, bg); - Gui.DrawRectangle(0, _top + 224, _left + 320 + _right, _top + 224 + _bottom, bg, bg); - } - uint mode = Mem.ReadByte(0xFFA555); - switch (mode) - { - case 0x20: - case 0x28: - case 0xAC: - //ClientApi.SetGameExtraPadding(160, 112, 160, 112); - if (_dumpMap <= 1) EccoDrawBoxes(); - // Uncomment the following block to enable mapdumping - if ((Mem.ReadU16(0xFFA7C8) > 1) && (Mem.ReadU16(0xFFA7C8) < 4)) - { - _dumpMap = 1; - _rowStateGuid = string.Empty; - _top = _bottom = _left = _right = 0; - ClientApi.SetGameExtraPadding(0, 0, 0, 0); - } - if (_dumpMap == 3) - { - var levelID = Mem.ReadS8(0xFFA7D0); - int[] nameGroupLengths = - { - 7,1,11,6, - 4,3,3,3, - 7,1,2,1, - 0,0,0,0 - }; - int[] nameStringPtrOffsets = - { - 0xECBD0, 0x106BC0, 0x10AF8C, 0x135A48, - 0x1558E8, 0x15F700, 0x16537C, 0x180B00, - 0x193920, 0x1B3ECC, 0x1D7A44, 0x1DBF70, - 0x2DF2, 0x2DF6, 0x2DFA, 0x2DFE - }; - int nameGroup = 0; - var i = levelID; - while ((i >= 0) && (nameGroup < nameGroupLengths.Length)) - { - i -= nameGroupLengths[nameGroup]; - if (i >= 0) nameGroup++; - } - string name = "map"; - if (i < 0) - { - i += nameGroupLengths[nameGroup]; - uint strOffset = Mem.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); - Console.WriteLine($"{i}"); - strOffset = Mem.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); - strOffset += 0x20; - List strTmp = new List(); - byte c; - do - { - c = (byte)Mem.ReadByte(strOffset++); - if (c != 0) - strTmp.Add(c); - } while (c != 0); - name = System.Text.Encoding.ASCII.GetString(strTmp.ToArray()); - TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; - name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); - } - ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_top.png"); - _destX = _destY = 0; - ClientApi.SetGameExtraPadding(0, 0, 0, 0); - _dumpMap++; - } - if (_dumpMap == 6) - { - var levelID = Mem.ReadS8(0xFFA7D0); - int[] nameGroupLengths = - { - 7,1,11,6, - 4,3,3,3, - 7,1,2,1, - 0,0,0,0 - }; - int[] nameStringPtrOffsets = - { - 0xECBD0, 0x106BC0, 0x10AF8C, 0x135A48, - 0x1558E8, 0x15F700, 0x16537C, 0x180B00, - 0x193920, 0x1B3ECC, 0x1D7A44, 0x1DBF70, - 0x2DF2, 0x2DF6, 0x2DFA, 0x2DFE - }; - int nameGroup = 0; - var i = levelID; - while ((i >= 0) && (nameGroup < nameGroupLengths.Length)) - { - i -= nameGroupLengths[nameGroup]; - if (i >= 0) nameGroup++; - } - string name = "map"; - if (i < 0) - { - i += nameGroupLengths[nameGroup]; - uint strOffset = Mem.ReadU32(nameStringPtrOffsets[nameGroup] + 0x2E); - Console.WriteLine($"{i}"); - strOffset = Mem.ReadU32(strOffset + ((i << 3) + (i << 5)) + 0x22); - strOffset += 0x20; - List strTmp = new List(); - byte c; - do - { - c = (byte)Mem.ReadByte(strOffset++); - if (c != 0) - strTmp.Add(c); - } while (c != 0); - name = System.Text.Encoding.ASCII.GetString(strTmp.ToArray()); - TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; - name = textInfo.ToTitleCase(name).Replace(" ", string.Empty); - } - ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}_{name}_bottom.png"); - _destX = _destY = 0; - _left = _right = 160; - _top = _bottom = 112; - ClientApi.SetGameExtraPadding(_left, _top, _right, _bottom); - _dumpMap = 0; - } - break; - case 0xF6: - EccoDraw3D(); - break; - default: - break; - } - _prevF = Mem.ReadU32(0xFFA524); - } - } - public override void PostFrameCallback() - { - uint frame = Mem.ReadU32(0xFFA524); - if ((frame <= _prevF) && !Emu.IsLagged()) - { - Emu.SetIsLagged(true); - Emu.SetLagCount(Emu.LagCount() + 1); - } - uint mode = Mem.ReadByte(0xFFA555); - _tickerY = 81; - string valueTicker = $"{Mem.ReadU32(0xFFA520)}:{Mem.ReadU32(0xFFA524)}:{Mem.ReadU16(0xFFA7C8)}:{mode:X2}"; - TickerText(valueTicker); - switch (mode) - { - case 0x20: - case 0x28: - case 0xAC: - valueTicker = $"{Mem.ReadS16(0xFFAD9C)}:{Mem.ReadS16(0xFFAD9E)}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFAA1A) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA1E) / 65536.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFAA32) / 65536.0:0.######}:{Mem.ReadU8(0xFFAA6D)}:{Mem.ReadU8(0xFFAA6E)}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFAA36) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA3A) / 65536.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFA9D6) / 65536.0:0.######}:{Mem.ReadS32(0xFFA9DA) / 65536.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFAA3E) / 65536.0:0.######}:{Mem.ReadS32(0xFFAA42) / 65536.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{(Mem.ReadS32(0xFFAA36) + Mem.ReadS32(0xFFA9D6) + Mem.ReadS32(0xFFAA3E)) / 65536.0:0.######}:" + - $"{(Mem.ReadS32(0xFFAA3A) + Mem.ReadS32(0xFFA9DA) + Mem.ReadS32(0xFFAA42)) / 65536.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadU8(0xFFAB72)}:{Mem.ReadU8(0xFFAB70)}:{(short)Mem.ReadS16(0xFFAA52):X4}:{(short)Mem.ReadS16(0xFFAA5A):X4}"; - TickerText(valueTicker); - switch (Mem.ReadU8(0xFFA7D0)) - { - case 1: - case 2: - case 3: - case 30: - case 46: - var globeFlags = Mem.ReadU32(0xFFD434) >> 1; - var globeFlags2 = Mem.ReadU32(0xFFD438) >> 1; - int i, j = i = 0; - while (globeFlags > 0) - { - globeFlags >>= 1; - i++; - } - while (globeFlags2 > 0) - { - globeFlags2 >>= 1; - j++; - } - TickerText($"{i}:{j}", Color.Blue); - break; - default: - break; - } - if (_dumpMap != 0) - { - Mem.WriteS16(0xFFAA16, 7); - Mem.WriteS16(0xFFAA18, 56); - int PlayerX = Mem.ReadS16(0xFFAA1A) - _camX; - int PlayerY = Mem.ReadS16(0xFFAA1E) - _camY; - if ((PlayerX < -64) || (PlayerX > 384) || (PlayerY < -64) || (PlayerY > 288)) - { - Mem.WriteByte(0xFFAA70, 0xC); - Mem.WriteS16(0xFFA7CA, 1); - } - else - { - Mem.WriteByte(0xFFAA70, 0x0); - Mem.WriteS16(0xFFA7CA, 0); - } - } - if (_dumpMap == 1) - { - int levelWidth = Mem.ReadS16(0xFFA7A8); - int levelHeight = Mem.ReadS16(0xFFA7AC); - var levelID = Mem.ReadByte(0xFFA7D0); - var s = Emu.GetSettings() as GPGX.GPGXSettings; - s.DrawBGA = false; - s.DrawBGB = false; - s.DrawBGW = false; - s.DrawObj = false; - s.Backdrop = true; - Emu.PutSettings(s); - if ((_camX == _destX) && (_camY == _destY)) - { - if ((_prevX != _camX) || (_prevY != _camY)) - { - if (_destX == 0) - { - if (_rowStateGuid != string.Empty) - { - MemSS.DeleteState(_rowStateGuid); - } - _rowStateGuid = MemSS.SaveCoreStateToMemory(); - } - _snapPast = 1; - } - else - { - _snapPast--; - } - if (_snapPast == 0) - { - ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_top.png"); - if (_destX >= levelWidth - 320) - { - if (_destY < levelHeight - 224) - { - if (_rowStateGuid != string.Empty) - { - MemSS.LoadCoreStateFromMemory(_rowStateGuid); - } - _destX = 0; - _destY = Math.Min(_destY + 111, levelHeight - 224); - } - } - else - _destX = Math.Min(_destX + 159, levelWidth - 320); - if ((_prevX == _destX) && (_prevY == _destY)) - { - ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); - _dumpMap++; - } - } - } - Mem.WriteS16(0xFFAD8C, _destX); - Mem.WriteS16(0xFFAD90, _destY); - } - else if (_dumpMap == 2) - { - if (_rowStateGuid != String.Empty) - MemSS.DeleteState(_rowStateGuid); - _rowStateGuid = String.Empty; - int levelWidth = Mem.ReadS16(0xFFA7A8); - int levelHeight = Mem.ReadS16(0xFFA7AC); - ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); - var levelID = Mem.ReadS8(0xFFA7D0); - var s = Emu.GetSettings() as GPGX.GPGXSettings; - s.DrawBGA = false; - s.DrawBGB = false; - s.DrawBGW = false; - s.DrawObj = false; - s.Backdrop = true; - Emu.PutSettings(s); - - var a = Gui.GetAttributes(); - a.SetColorKey(Color.FromArgb(0, 0x11, 0x22, 0x33), Color.FromArgb(0, 0x11, 0x22, 0x33)); - Gui.SetAttributes(a); - Gui.ToggleCompositingMode(); - - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_top.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); - for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) - { - var dx = (x == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_top.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); - } - for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) - { - var dy = (y == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_top.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); - for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) - { - var dx = (x == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_top.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); - } - } - - Gui.ToggleCompositingMode(); - Gui.SetAttributes(new System.Drawing.Imaging.ImageAttributes()); - Gui.DrawFinish(); - _dumpMap++; - } - else if (_dumpMap == 4) - { - int levelWidth = Mem.ReadS16(0xFFA7A8); - int levelHeight = Mem.ReadS16(0xFFA7AC); - var levelID = Mem.ReadByte(0xFFA7D0); - var s = Emu.GetSettings() as GPGX.GPGXSettings; - s.DrawBGA = (levelID != 29); - s.DrawBGB = (levelID == 7); - s.DrawBGW = true; - s.DrawObj = true; - s.Backdrop = false; - Emu.PutSettings(s); - if ((_camX == _destX) && (_camY == _destY)) - { - if ((_prevX != _camX) || (_prevY != _camY)) - { - if (_destX == 0) - { - if (_rowStateGuid != string.Empty) - { - MemSS.DeleteState(_rowStateGuid); - } - _rowStateGuid = MemSS.SaveCoreStateToMemory(); - } - _snapPast = 1; - } - else - { - _snapPast--; - } - if (_snapPast == 0) - { - ClientApi.Screenshot($"c:\\Ecco2Maps\\{levelID}\\{_destY}_{_destX}_bottom.png"); - if (_destX >= levelWidth - 320) - { - if (_destY < levelHeight - 224) - { - if (_rowStateGuid != string.Empty) - { - MemSS.LoadCoreStateFromMemory(_rowStateGuid); - } - _destX = 0; - _destY = Math.Min(_destY + 111, levelHeight - 224); - } - } - else - _destX = Math.Min(_destX + 159, levelWidth - 320); - if ((_prevX == _destX) && (_prevY == _destY)) - { - ClientApi.SetGameExtraPadding(levelWidth - 320, levelHeight - 224, 0, 0); - _dumpMap++; - } - } - } - Mem.WriteS16(0xFFAD8C, _destX); - Mem.WriteS16(0xFFAD90, _destY); - } - else if (_dumpMap == 5) - { - if (_rowStateGuid != String.Empty) - MemSS.DeleteState(_rowStateGuid); - _rowStateGuid = String.Empty; - int levelWidth = Mem.ReadS16(0xFFA7A8); - int levelHeight = Mem.ReadS16(0xFFA7AC); - var levelID = Mem.ReadS8(0xFFA7D0); - var s = Emu.GetSettings() as GPGX.GPGXSettings; - s.DrawBGA = (levelID != 29); - s.DrawBGB = (levelID == 7); - s.DrawBGW = true; - s.DrawObj = true; - s.Backdrop = false; - Emu.PutSettings(s); - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{levelWidth - 320}_bottom.png", 2, 2, 318, 222, (levelWidth - 318), (levelHeight - 222), 318, 222); - for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) - { - var dx = (x == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{levelHeight - 224}_{x}_bottom.png", dx, 2, 320 - dx, 222, x + dx, (levelHeight - 222), 320 - dx, 222); - } - for (int y = ((levelHeight - 224) / 111) * 111; y >= 0; y -= 111) - { - var dy = (y == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{levelWidth - 320}_bottom.png", 2, dy, 318, 224 - 2, levelWidth - 318, y + dy, 318, 224 - dy); - for (int x = ((levelWidth - 320) / 159) * 159; x >= 0; x -= 159) - { - var dx = (x == 0) ? 0 : 2; - Gui.DrawImageRegion($"c:\\Ecco2Maps\\{levelID}\\{y}_{x}_bottom.png", dx, dy, 320 - dx, 224 - dy, x + dx, y + dy, 320 - dx, 224 - dy); - } - } - Gui.DrawFinish(); - _dumpMap++; - } - _prevX = _camX; - _prevY = _camY; - break; - case 0xF6: - valueTicker = $"{Mem.ReadS32(0xFFD5E0) / 4096.0:0.######}:{Mem.ReadS32(0xFFD5E8) / 4096.0:0.######}:{Mem.ReadS32(0xFFD5E4) / 2048.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFB13A) / 4096.0:0.######}:{Mem.ReadS32(0xFFB142) / 4096.0:0.######}:{Mem.ReadS32(0xFFB13E) / 2048.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadS32(0xFFB162) / 4096.0:0.######}:{Mem.ReadS32(0xFFB16A) / 4096.0:0.######}:{Mem.ReadS32(0xFFB166) / 2048.0:0.######}"; - TickerText(valueTicker); - valueTicker = $"{Mem.ReadU8(0xFFB19B)}:{Mem.ReadU8(0xFFB1A6)}:{Mem.ReadU8(0xFFB1A9)}"; - TickerText(valueTicker); - int SpawnZ = Mem.ReadS32(0xFFD5F0) + 0x180000; - int nextRingZ = SpawnZ; - while (((nextRingZ >> 17) & 0xF) != 0) - { - nextRingZ += 0x20000; - } - valueTicker = $"{Mem.ReadS32(0xFFD856) / 4096.0:0.######}:{Mem.ReadS32(0xFFD85A) / 4096.0:0.######}:{(nextRingZ - 0x160000) / 2048.0:0.######}:{nextRingZ / 2048.0:0.######}"; - TickerText(valueTicker); - var levelId = -1 - Mem.ReadS16(0xFFA79E); - bool spawn = false; - bool firstRand = true; - int SpawnX, SpawnY, z; - int CamX = (Mem.ReadS32(0xFFD5E0) >> 0xC) - _left; - int CamY = (Mem.ReadS32(0xFFD5E8) >> 0xC) + _top; - int CamZ = (Mem.ReadS32(0xFFD5E4) >> 0xC) + _top; - while (!spawn) - { - var temp = (SpawnZ >> 17) & 0xFF; - var controlList = Mem.ReadS32(0x7B54 + (levelId << 2)); - temp = Mem.ReadS16(controlList + (temp << 1)); - var v = temp & 0xFF; - var num = (temp >> 8) + v; - temp = v; - spawn = (num > 2); - if (spawn) for (; temp < num; temp++) - { - switch (temp) - { - case 0: - case 1: - case 13: - // Nothing important spawns - break; - case 2: - // Jellyfish - SpawnX = Mem.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); - firstRand = false; - SpawnY = -0xC0000 + (EccoRand() << 3); - z = SpawnZ + 0x20000;// ? - valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; - TickerText(valueTicker); - SpawnX = 160 + ((SpawnX >> 0xC) - CamX); - SpawnY = 112 - ((SpawnY >> 0xC) - CamY); - z = _top + 112 - ((z >> 0xC) - CamZ); - DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); - DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); - break; - case 3: - // Eagle - SpawnX = Mem.ReadS32(0xFFB13A) + 0x40000 - (EccoRand(firstRand) << 3); - firstRand = false; - SpawnY = 0x50000; - z = SpawnZ - 0x40000 + 0x20000;// ? - valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; - TickerText(valueTicker); - SpawnX = 160 + ((SpawnX >> 0xC) - CamX); - SpawnY = 112 - ((SpawnY >> 0xC) - CamY); - z = _top + 112 - ((z >> 0xC) - CamZ); - DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); - DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); - break; - case 4: - // Shark - bool left = (EccoRand(firstRand) > 0x8000); - firstRand = false; - var xdiff = 0xC0000 + (EccoRand() << 3); - SpawnX = Mem.ReadS32(0xFFB13A) + (left ? -xdiff : xdiff); - SpawnY = Math.Min(Mem.ReadS32(0xFFB142), -0x10000) - (EccoRand() + 0x10000); - z = SpawnZ + 0x20000; - valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{z / 2048.0:0.######}"; - TickerText(valueTicker); - SpawnX = 160 + ((SpawnX >> 0xC) - CamX); - SpawnY = 112 - ((SpawnY >> 0xC) - CamY); - z = _top + 112 - ((z >> 0xC) - CamZ); - DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); - DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); - break; - case 5: - case 6: - case 7: - case 8: - // Vine - EccoRand(firstRand); - firstRand = false; - if ((temp & 1) == 1) EccoRand(); - EccoRand(); - break; - case 9: - case 10: - case 11: - case 12: - // Unknown, possibly just rand incrementation? - EccoRand(firstRand); - firstRand = false; - if ((temp & 1) == 1) EccoRand(); - break; - case 14: - // Shell - SpawnX = Mem.ReadS32(0xFFB13A) - 0x20000 + (EccoRand(firstRand) << 2); - firstRand = false; - SpawnY = -0x80000; - z = SpawnZ + 0x20000; - EccoRand(); - valueTicker = $"{SpawnX / 4096.0:0.######}:{SpawnY / 4096.0:0.######}:{(z - 0x180000) / 2048.0:0.######}:{(z - 0x80000) / 2048.0:0.######}"; - TickerText(valueTicker); - SpawnX = 160 + ((SpawnX >> 0xC) - CamX); - SpawnY = 112 - ((SpawnY >> 0xC) - CamY); - z = _top + 112 - ((z >> 0xC) - CamZ); - DrawBoxMWH(SpawnX, SpawnY, 1, 1, Color.Gray); - DrawBoxMWH(SpawnX, z, 1, 1, Color.Gray); - break; - } - } - SpawnZ += 0x20000; - } - break; - } - Joy.Set("C", null, 1); - Joy.Set("Start", null, 1); - var color = _turnSignalColors[Mem.ReadS8(0xFFA7C9) & 7]; - Gui.DrawRectangle(_left - 48, _top - 112, 15, 15, color, color); - } - public override void LoadStateCallback(string name) - { - Gui.DrawNew("emu"); - PreFrameCallback(); - Gui.DrawFinish(); - } - } -} diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index d12517e315..fd0185f1b6 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -658,7 +658,6 @@ - From 8a9e8ceed21d8a9284d519bdc1b8485beb61fa75 Mon Sep 17 00:00:00 2001 From: upthorn Date: Fri, 4 Jan 2019 14:25:24 -0800 Subject: [PATCH 028/440] Fix appveyor build error by removing use of C#7 features. --- BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs b/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs index 3677007d2b..a3cda9ed76 100644 --- a/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/EmuApi.cs @@ -97,7 +97,8 @@ namespace BizHawk.Client.ApiHawk domain = MemoryDomains[name]; } - var d = DisassemblableCore.Disassemble(domain, pc, out int l); + int l; + var d = DisassemblableCore.Disassemble(domain, pc, out l); return new { disasm = d, length = l }; } catch (NotImplementedException) From 303e9df26e5685f9abb51c5d88120544141f9643 Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 4 Jan 2019 17:41:59 -0500 Subject: [PATCH 029/440] rejigger PlatformLinkedLibSingleton so it can be used embedded in the EXE without requiring a dependency on dlls, so it can boot when dlls are relocated --- .../BizHawk.Client.EmuHawk.csproj | 7 +++++-- BizHawk.Client.EmuHawk/Program.cs | 12 ++++++------ BizHawk.Common/PlatformLinkedLibSingleton.cs | 17 ++++++++++++----- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 2587f62945..0a3bf56323 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -45,7 +45,7 @@ true ..\output\ - WINDOWS;DEBUG + DEBUG;WINDOWS;EXE_PROJECT true full AnyCPU @@ -56,7 +56,7 @@ ..\output\ - WINDOWS + WINDOWS;EXE_PROJECT true true pdbonly @@ -113,6 +113,9 @@ + + PlatformLinkedLibSingleton.cs + svnrev.cs diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index cc970daf55..0ed765e047 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -23,14 +23,14 @@ namespace BizHawk.Client.EmuHawk Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - var libLoader = PlatformLinkedLibSingleton.LinkedLibManager; + var libLoader = EXE_PROJECT.PlatformLinkedLibSingleton.LinkedLibManager; //http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips //try loading libraries we know we'll need //something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing //but oddly it lets us proceed and we'll then catch it here - var libExt = PlatformLinkedLibSingleton.RunningOnUnix ? ".dll.so" : ".dll"; + var libExt = EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix ? ".dll.so" : ".dll"; var d3dx9 = libLoader.LoadPlatformSpecific($"d3dx9_43{libExt}"); var vc2015 = libLoader.LoadPlatformSpecific($"vcruntime140{libExt}"); var vc2012 = libLoader.LoadPlatformSpecific($"msvcr120{libExt}"); //TODO - check version? @@ -65,7 +65,7 @@ namespace BizHawk.Client.EmuHawk libLoader.FreePlatformSpecific(vc2010); libLoader.FreePlatformSpecific(vc2010p); - if (!PlatformLinkedLibSingleton.RunningOnUnix) + if (!EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix) { // this will look in subdirectory "dll" to load pinvoked stuff string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); @@ -200,7 +200,7 @@ namespace BizHawk.Client.EmuHawk } } } - private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = PlatformLinkedLibSingleton.RunningOnUnix + private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificMainLoopCrashHandler) new UnixMonoMainLoopCrashHandler() : (PlatformSpecificMainLoopCrashHandler) new Win32MainLoopCrashHandler(); @@ -265,7 +265,7 @@ namespace BizHawk.Client.EmuHawk GlobalWin.GLManager = GLManager.Instance; //now create the "GL" context for the display method. we can reuse the IGL_TK context if opengl display method is chosen - if (PlatformLinkedLibSingleton.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; + if (EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; REDO_DISPMETHOD: if (Global.Config.DispMethod == Config.EDispMethod.GdiPlus) GlobalWin.GL = new Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus(); @@ -313,7 +313,7 @@ namespace BizHawk.Client.EmuHawk goto REDO_DISPMETHOD; } - if (!PlatformLinkedLibSingleton.RunningOnUnix) + if (!EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix) { //WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff. //The relevant initialization happened just before in "create IGL context". diff --git a/BizHawk.Common/PlatformLinkedLibSingleton.cs b/BizHawk.Common/PlatformLinkedLibSingleton.cs index 9a9ed2baab..14ed9c29e6 100644 --- a/BizHawk.Common/PlatformLinkedLibSingleton.cs +++ b/BizHawk.Common/PlatformLinkedLibSingleton.cs @@ -1,9 +1,16 @@ using System; -using System.Runtime.InteropServices; - +using System.Runtime.InteropServices; + +//put in a different namespace for EXE so we can have an instance of this type (by linking to this file rather than copying it) built-in to the exe +//so the exe doesnt implicitly depend on the dll +#if EXE_PROJECT +namespace EXE_PROJECT +#else namespace BizHawk.Common -{ - public sealed class PlatformLinkedLibSingleton +#endif +{ + +public sealed class PlatformLinkedLibSingleton { public static readonly bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; @@ -83,4 +90,4 @@ namespace BizHawk.Common } } } -} \ No newline at end of file +} From b9094545db80e464150347bdf135cc07c1d9b38e Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 4 Jan 2019 18:03:34 -0600 Subject: [PATCH 030/440] update 7zip file location --- BizHawk.Client.Common/7z/LibraryManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.Common/7z/LibraryManager.cs b/BizHawk.Client.Common/7z/LibraryManager.cs index 8f0d8c4b68..ac0aedd2ee 100644 --- a/BizHawk.Client.Common/7z/LibraryManager.cs +++ b/BizHawk.Client.Common/7z/LibraryManager.cs @@ -63,7 +63,7 @@ namespace SevenZip /// 7z.dll (from the 7-zip distribution) supports every InArchiveFormat for encoding and decoding. /// //private static string _libraryFileName = ConfigurationManager.AppSettings["7zLocation"] ?? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll"); - private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "7z.dll"); + private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "dll\\7z.dll"); #endif #if WINCE From e2ccff1c821f93371bc9666b15c7b02b0d00f355 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 5 Jan 2019 08:23:16 -0600 Subject: [PATCH 031/440] GBHawk: CGB double speed linking --- .../Consoles/Nintendo/GBHawk/SerialPort.cs | 28 +++++++++++++++++-- .../GBHawkLink/GBHawkLink.IEmulator.cs | 8 +++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs index 4aa700268c..f5e0150c61 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs @@ -49,7 +49,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if ((value & 1) > 0) { clk_internal = true; - clk_rate = 512; + if (((value & 2) > 0) && Core.GBC_compat) + { + clk_rate = 256; + } + else + { + clk_rate = 512; + } serial_clock = clk_rate; } else @@ -64,7 +71,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if ((value & 1) > 0) { clk_internal = true; - clk_rate = 512; + if (((value & 2) > 0) && Core.GBC_compat) + { + clk_rate = 256; + } + else + { + clk_rate = 512; + } serial_clock = clk_rate; } else @@ -75,7 +89,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1 + if (Core.GBC_compat) + { + serial_control = (byte)(0x7C | (value & 0x83)); // extra CGB bit + } + else + { + serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1 + } + break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 0a95188026..48ce21972b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -105,7 +105,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink R.do_single_step(); // the signal to shift out a bit is when serial_clock = 1 - if (L.serialport.serial_clock == 1) + if ((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) { if (LinkConnected) { @@ -113,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink if ((R.serialport.clk_rate == -1) && R.serialport.serial_start) { - R.serialport.serial_clock = 1; + R.serialport.serial_clock = L.serialport.serial_clock; R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); R.serialport.coming_in = L.serialport.going_out; } @@ -121,7 +121,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink L.serialport.coming_in = R.serialport.going_out; } } - else if (R.serialport.serial_clock == 1) + else if ((R.serialport.serial_clock == 1) || (R.serialport.serial_clock == 2)) { if (LinkConnected) { @@ -129,7 +129,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink if ((L.serialport.clk_rate == -1) && L.serialport.serial_start) { - L.serialport.serial_clock = 1; + L.serialport.serial_clock = R.serialport.serial_clock; L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80)); L.serialport.coming_in = R.serialport.going_out; } From 292ee296dc116cca0f0c403a4d72fd106141a209 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 5 Jan 2019 10:34:19 -0600 Subject: [PATCH 032/440] GBHAwk: palette not writable during rendering: fixes lego racers --- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index b02084f64b..27775f026b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0xFF54: ret = HDMA_dest_lo; break; // HDMA4 case 0xFF55: ret = HDMA_ctrl; break; // HDMA5 case 0xFF68: ret = BG_pal_ret; break; // BGPI - case 0xFF69: ret = BG_bytes[BG_bytes_index]; break; // BGPD + case 0xFF69: ret = BG_PAL_read(); break; // BGPD case 0xFF6A: ret = OBJ_pal_ret; break; // OBPI case 0xFF6B: ret = OBJ_bytes[OBJ_bytes_index]; break; // OBPD } @@ -90,6 +90,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk return ret; } + public byte BG_PAL_read() + { + if (VRAM_access_read) + { + return BG_bytes[BG_bytes_index]; + } + else + { + return 0xFF; + } + } + public override void WriteReg(int addr, byte value) { switch (addr) @@ -240,8 +252,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk BG_bytes_inc = ((value & 0x80) == 0x80); break; case 0xFF69: // BGPD - BG_transfer_byte = value; - BG_bytes[BG_bytes_index] = value; + if (VRAM_access_write) + { + BG_transfer_byte = value; + BG_bytes[BG_bytes_index] = value; + } // change the appropriate palette color color_compute_BG(); From cd2d63b04a0844cecef1d1d4a273ecc1422ef654 Mon Sep 17 00:00:00 2001 From: feos Date: Sat, 5 Jan 2019 21:30:06 +0300 Subject: [PATCH 033/440] tastudio: - don't use branch laglog after loading it. it's useless because we invalidate if needed anyway - PauseOnFrame being null started to crash seeking, fixed - make use of movie alias in branchbox - capture tsm state after loading the branch todo: if we load a branch in the middle of invalid greenzone, advancing won't draw new greenzone even tho states are being created. laglog doesn't seem to allow gaps either. unsure how to resolve --- .../movie/tasproj/TasMovie.cs | 8 ++------ BizHawk.Client.EmuHawk/MainForm.cs | 2 +- .../tools/TAStudio/BookmarksBranchesBox.cs | 19 ++++++++++--------- .../tools/TAStudio/TAStudio.cs | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index e500a1e833..80b54f7c9a 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -509,17 +509,13 @@ namespace BizHawk.Client.Common Log?.Dispose(); Log = branch.InputLog.Clone(); - _lagLog.FromLagLog(branch.LagLog); - - // if there are branch states, they will be loaded anyway - // but if there's none, or only *after* divergent point, don't invalidate the entire movie anymore if (divergentPoint.HasValue) { - _stateManager.Invalidate(divergentPoint.Value); + InvalidateAfter(divergentPoint.Value); } else { - _stateManager.Invalidate(branch.InputLog.Count); + InvalidateAfter(branch.InputLog.Count); } if (BindMarkersToInput) // pretty critical not to erase them diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 4c02e8bf16..28f0311d31 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3060,11 +3060,11 @@ namespace BizHawk.Client.EmuHawk if (IsSeeking && Emulator.Frame == PauseOnFrame.Value) { PauseEmulator(); - PauseOnFrame = null; if (GlobalWin.Tools.IsLoaded()) { GlobalWin.Tools.TAStudio.StopSeeking(); } + PauseOnFrame = null; } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs index 8e7adcc47b..f64cace517 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs @@ -117,7 +117,7 @@ namespace BizHawk.Client.EmuHawk TasBranch branch = GetBranch(index); if (branch != null) { - var record = Tastudio.CurrentTasMovie[branch.Frame]; + var record = Movie[branch.Frame]; if (index == Movie.CurrentBranch) { color = TAStudio.CurrentFrame_InputLog; @@ -146,7 +146,7 @@ namespace BizHawk.Client.EmuHawk private TasBranch GetBranch(int index) { - return Tastudio.CurrentTasMovie.GetBranch(index); + return Movie.GetBranch(index); } public void Branch() @@ -199,13 +199,14 @@ namespace BizHawk.Client.EmuHawk return; } - Tastudio.CurrentTasMovie.LoadBranch(branch); + Movie.LoadBranch(branch); var stateInfo = new KeyValuePair(branch.Frame, branch.CoreData); Tastudio.LoadState(stateInfo); + Movie.TasStateManager.Capture(true); QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.OSDFrameBuffer), Tastudio.VideoProvider); if (Tastudio.Settings.OldControlSchemeForBranches && Tastudio.TasPlaybackBox.RecordingMode) - Tastudio.CurrentTasMovie.Truncate(branch.Frame); + Movie.Truncate(branch.Frame); GlobalWin.MainForm.PauseOnFrame = null; Tastudio.RefreshDialog(); @@ -242,7 +243,7 @@ namespace BizHawk.Client.EmuHawk private void AddBranchToolStripMenuItem_Click(object sender, EventArgs e) { Branch(); - CallSavedCallback(Tastudio.CurrentTasMovie.BranchCount - 1); + CallSavedCallback(Movie.BranchCount - 1); GlobalWin.OSD.AddMessage("Added branch " + Movie.CurrentBranch.ToString()); } @@ -250,7 +251,7 @@ namespace BizHawk.Client.EmuHawk { Branch(); EditBranchTextPopUp(Movie.CurrentBranch); - CallSavedCallback(Tastudio.CurrentTasMovie.BranchCount - 1); + CallSavedCallback(Movie.BranchCount - 1); GlobalWin.OSD.AddMessage("Added branch " + Movie.CurrentBranch.ToString()); } @@ -366,13 +367,13 @@ namespace BizHawk.Client.EmuHawk if (_branchUndo == BranchUndo.Load) { LoadBranch(_backupBranch); - CallLoadedCallback(Tastudio.CurrentTasMovie.Branches.IndexOf(_backupBranch)); + CallLoadedCallback(Movie.Branches.IndexOf(_backupBranch)); GlobalWin.OSD.AddMessage("Branch Load canceled"); } else if (_branchUndo == BranchUndo.Update) { Movie.UpdateBranch(Movie.GetBranch(_backupBranch.UniqueIdentifier), _backupBranch); - CallSavedCallback(Tastudio.CurrentTasMovie.Branches.IndexOf(_backupBranch)); + CallSavedCallback(Movie.Branches.IndexOf(_backupBranch)); GlobalWin.OSD.AddMessage("Branch Update canceled"); } else if (_branchUndo == BranchUndo.Text) @@ -384,7 +385,7 @@ namespace BizHawk.Client.EmuHawk { Movie.AddBranch(_backupBranch); BranchView.RowCount = Movie.BranchCount; - CallSavedCallback(Tastudio.CurrentTasMovie.Branches.IndexOf(_backupBranch)); + CallSavedCallback(Movie.Branches.IndexOf(_backupBranch)); GlobalWin.OSD.AddMessage("Branch Removal canceled"); } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 0019b8e3eb..8b0647d1f6 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -191,7 +191,7 @@ namespace BizHawk.Client.EmuHawk this.Invoke(() => SavingProgressBar.Visible = true); for (;;) { - if (_seekBackgroundWorker.CancellationPending || !this.IsHandleCreated) + if (_seekBackgroundWorker.CancellationPending || !IsHandleCreated || !Mainform.PauseOnFrame.HasValue) { e.Cancel = true; break; From 56e77f490723d1b6bc08de0accbd8dba21108924 Mon Sep 17 00:00:00 2001 From: feos Date: Sat, 5 Jan 2019 21:48:40 +0300 Subject: [PATCH 034/440] tastudio: allow to actually unbind markers from input, and unbind by default --- BizHawk.Client.Common/movie/tasproj/TasMovie.cs | 4 ++-- BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 80b54f7c9a..a226d2d17f 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -65,7 +65,7 @@ namespace BizHawk.Client.Common Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on"); - BindMarkersToInput = true; + BindMarkersToInput = false; CurrentBranch = -1; } @@ -84,7 +84,7 @@ namespace BizHawk.Client.Common Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on"); - BindMarkersToInput = true; + BindMarkersToInput = false; CurrentBranch = -1; } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 013f04ea77..f2eb9db437 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -822,6 +822,7 @@ namespace BizHawk.Client.EmuHawk SingleClickFloatEditMenuItem.Checked = Settings.SingleClickFloatEdit; OldControlSchemeForBranchesMenuItem.Checked = Settings.OldControlSchemeForBranches; LoadBranchOnDoubleclickMenuItem.Checked = Settings.LoadBranchOnDoubleClick; + BindMarkersToInputMenuItem.Checked = CurrentTasMovie.BindMarkersToInput; } private void SetMaxUndoLevelsMenuItem_Click(object sender, EventArgs e) From 3a8ae031d33763f6ba445a2e56841845c60cb0b9 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 5 Jan 2019 13:00:37 -0600 Subject: [PATCH 035/440] GBHawkLink: Fix state error. --- .../Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs | 5 ----- .../Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 48ce21972b..1cebe9f5b4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -14,11 +14,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public byte controller_state; - public bool in_vblank_old; - public bool in_vblank; - public bool vblank_rise; - public void FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs index ffd05ea99f..5429566225 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -60,6 +60,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink ser.Sync("_cableconnected", ref _cableconnected); ser.Sync("_cablediscosignal", ref _cablediscosignal); _controllerDeck.SyncState(ser); + + LinkConnected = _cableconnected; } } } From b962f06e07cc5ab968816c72dd20e3a526e56722 Mon Sep 17 00:00:00 2001 From: Dan B Date: Sun, 6 Jan 2019 12:16:28 -0500 Subject: [PATCH 036/440] Fix quicknes --- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index fc632d8fa9..899ae0254f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -21,7 +21,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { static QuickNES() { - QN = BizInvoker.GetInvoker(new DynamicLibraryImportResolver(LibQuickNES.dllname), CallingConventionAdapters.Native); + Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname); + QN = BizInvoker.GetInvoker(Resolver, CallingConventionAdapters.Native); QN.qn_setup_mappers(); } @@ -73,6 +74,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES } static readonly LibQuickNES QN; + static readonly DynamicLibraryImportResolver Resolver; public IEmulatorServiceProvider ServiceProvider { get; private set; } From c0a28a320b873c1a07316760e8e6aed8c1154da1 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Mon, 7 Jan 2019 22:01:57 +1000 Subject: [PATCH 037/440] Inconsequential changes (no whitespace) Remove useless semicolon, remove useless `? true : false`, move period to next line --- BizHawk.Client.DiscoHawk/DiscoHawkDialog.cs | 2 +- .../tools/BasicBot/BasicBot.cs | 4 ++-- .../CPUs/LR35902/Operations.cs | 2 +- BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs | 2 +- .../Media/Tape/PZX/PzxConverter.cs | 4 ++-- .../Consoles/Atari/A7800Hawk/A7800Hawk.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_MBC2.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_MBC3.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_MBC7.cs | 4 ++-- .../Consoles/Nintendo/NES/Boards/Cony.cs | 2 +- .../Consoles/Nintendo/NES/Boards/Mapper222.cs | 16 ++++++++-------- .../Consoles/Nintendo/NES/PPU.cs | 2 +- .../Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/BizHawk.Client.DiscoHawk/DiscoHawkDialog.cs b/BizHawk.Client.DiscoHawk/DiscoHawkDialog.cs index 557d15aa87..14992bcf97 100644 --- a/BizHawk.Client.DiscoHawk/DiscoHawkDialog.cs +++ b/BizHawk.Client.DiscoHawk/DiscoHawkDialog.cs @@ -95,7 +95,7 @@ namespace BizHawk.Client.DiscoHawk } var cueBin = boundDisc.DumpCueBin(boundDiscRecord.BaseName, GetCuePrefs()); - txtCuePreview.Text = cueBin.cue.Replace("\n", "\r\n"); ; + txtCuePreview.Text = cueBin.cue.Replace("\n", "\r\n"); } private void btnPresetCanonical_Click(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs index 2c6392854c..5c3e484926 100644 --- a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs +++ b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs @@ -350,8 +350,8 @@ namespace BizHawk.Client.EmuHawk set { - var item = StartFromSlotBox.Items. - OfType() + var item = StartFromSlotBox.Items + .OfType() .FirstOrDefault(o => o.ToString() == value); if (item != null) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Operations.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Operations.cs index e317416265..cddd89dd72 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Operations.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Operations.cs @@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 public void SRL_Func(ushort src) { - FlagC = Regs[src].Bit(0) ? true : false; + FlagC = Regs[src].Bit(0); Regs[src] = (ushort)(Regs[src] >> 1); diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs index d643ce06c8..1212430187 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -267,7 +267,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public void SRL_Func(ushort src) { - FlagC = Regs[src].Bit(0) ? true : false; + FlagC = Regs[src].Bit(0); Regs[src] = (ushort)(Regs[src] >> 1); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs index 6ada823be8..ed35aadf55 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/PZX/PzxConverter.cs @@ -249,7 +249,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum dCount = GetInt32(b, pos); initPulseLevel = (uint)((dCount & 0x80000000) == 0 ? 0 : 1); - t.InitialPulseLevel = initPulseLevel == 1 ? true : false; + t.InitialPulseLevel = initPulseLevel == 1; dCount = (int)(dCount & 0x7FFFFFFF); pos += 4; @@ -334,7 +334,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum var d = GetInt32(b, pos); iniPulseLevel = ((d & 0x80000000) == 0 ? 0 : 1); - t.InitialPulseLevel = iniPulseLevel == 1 ? true : false; + t.InitialPulseLevel = iniPulseLevel == 1; pCount = (d & 0x7FFFFFFF); // convert to tape block diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs index 7d64189dca..2651c1f893 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs @@ -172,7 +172,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk byte cart_1 = header[0x35]; byte cart_2 = header[0x36]; - _isPAL = (header[0x39] > 0) ? true : false; + _isPAL = (header[0x39] > 0); if (cart_2.Bit(1)) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs index 06f64f781a..3d84b4fde2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs @@ -120,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (addr < 0x2000) { - RAM_enable = ((value & 0xA) == 0xA) ? true : false; + RAM_enable = ((value & 0xA) == 0xA); } else if (addr < 0x4000) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs index e18a829d62..9d82306f50 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs @@ -81,7 +81,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if ((addr & 0x100) == 0) { - RAM_enable = ((value & 0xA) == 0xA) ? true : false; + RAM_enable = ((value & 0xA) == 0xA); } } else if (addr < 0x4000) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs index 840bc5ba37..f52c8c6e65 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs @@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (addr < 0x2000) { - RAM_enable = ((value & 0xA) == 0xA) ? true : false; + RAM_enable = ((value & 0xA) == 0xA); } else if (addr < 0x4000) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC7.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC7.cs index 1e733479de..ba00d55c9d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC7.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC7.cs @@ -419,11 +419,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 5: if ((instr_clocks >= 0) && (instr_clocks <= 7)) { - DO = ((Core.cart_RAM[EE_addr * 2 + 1] >> (7 - instr_clocks)) & 1) == 1 ? true : false; + DO = ((Core.cart_RAM[EE_addr * 2 + 1] >> (7 - instr_clocks)) & 1) == 1; } else if ((instr_clocks >= 8) && (instr_clocks <= 15)) { - DO = ((Core.cart_RAM[EE_addr * 2] >> (15 - instr_clocks)) & 1) == 1 ? true : false; + DO = ((Core.cart_RAM[EE_addr * 2] >> (15 - instr_clocks)) & 1) == 1; } if (instr_clocks == 15) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Cony.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Cony.cs index b1ac0da1c2..3decb3fb74 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Cony.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Cony.cs @@ -451,7 +451,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES else if (addr == 0x200) { - IRQCount &= 0xFF00; IRQCount |= value; ; + IRQCount &= 0xFF00; IRQCount |= value; IRQSignal = false; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper222.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper222.cs index d249370787..52607fcd15 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper222.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper222.cs @@ -66,14 +66,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //Console.WriteLine("IRQ GO: SL {0} val {1}", NES.ppu.ppur.status.sl, value); //break; case 0x1000: SetMirrorType(!value.Bit(0) ? EMirrorType.Vertical : EMirrorType.Horizontal);break; - case 0x3000: chr[0] = value & chr_bank_mask_1k; ; break; - case 0x3002: chr[1] = value & chr_bank_mask_1k; ; break; - case 0x4000: chr[2] = value & chr_bank_mask_1k; ; break; - case 0x4002: chr[3] = value & chr_bank_mask_1k; ; break; - case 0x5000: chr[4] = value & chr_bank_mask_1k; ; break; - case 0x5002: chr[5] = value & chr_bank_mask_1k; ; break; - case 0x6000: chr[6] = value & chr_bank_mask_1k; ; break; - case 0x6002: chr[7] = value & chr_bank_mask_1k; ; break; + case 0x3000: chr[0] = value & chr_bank_mask_1k; break; + case 0x3002: chr[1] = value & chr_bank_mask_1k; break; + case 0x4000: chr[2] = value & chr_bank_mask_1k; break; + case 0x4002: chr[3] = value & chr_bank_mask_1k; break; + case 0x5000: chr[4] = value & chr_bank_mask_1k; break; + case 0x5002: chr[5] = value & chr_bank_mask_1k; break; + case 0x6000: chr[6] = value & chr_bank_mask_1k; break; + case 0x6002: chr[7] = value & chr_bank_mask_1k; break; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 36df0ab4c3..0fb724ce31 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -307,7 +307,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES string str = "oamdata" + i.ToString() + "y"; oam_byte = t_oam[i].oam_y; ser.Sync(str, ref oam_byte); t_oam[i].oam_y = oam_byte; str = "oamdata" + i.ToString() + "ind"; - oam_byte = t_oam[i].oam_ind; ; ser.Sync(str, ref oam_byte); t_oam[i].oam_ind = oam_byte; + oam_byte = t_oam[i].oam_ind; ser.Sync(str, ref oam_byte); t_oam[i].oam_ind = oam_byte; str = "oamdata" + i.ToString() + "attr"; oam_byte = t_oam[i].oam_attr; ser.Sync(str, ref oam_byte); t_oam[i].oam_attr = oam_byte; str = "oamdata" + i.ToString() + "x"; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs index 9eaa69b291..69f2250c13 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IVideoProvider.cs @@ -78,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx for (int i = 0; i < xpad; i++) *pdst++ = unchecked((int)0xff000000); for (int i = 0; i < gpwidth; i++) - *pdst++ = *psrc++; ; + *pdst++ = *psrc++; for (int i = 0; i < xpad2; i++) *pdst++ = unchecked((int)0xff000000); psrc += rinc; From 5f642845e710cd56981ae8f4af0d64c65a1bf598 Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 8 Jan 2019 16:08:37 +1000 Subject: [PATCH 038/440] draft 1 --- README.md | 89 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 05d9dd6cda..18ec806b05 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,84 @@ # BizHawk +![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat) + BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as fullscreen, rewind, and joypad support in addition to rerecording and debugging tools for all system cores. -[Release Notes](http://tasvideos.org/Bizhawk/ReleaseHistory.html) +## Installing — Windows 7/8.1/10 + +Released binaries can be found right here on GitHub: + +[![Windows | binaries](https://img.shields.io/badge/Windows-binaries-%230078D6.svg?logo=windows&logoColor=0078D6&style=popout)](http://github.com/TASVideos/BizHawk/releases) + +Click `BizHawk-.zip` to download it. Also note the changelog, the full version of which is [on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix different versions** of BizHawk, keep each version in its own folder. + +Before you start (by running `EmuHawk.exe`), make sure you have the Windows-only prerequisites installed: .NET Framework 4.6.1; Visual C++ 2010 SP1, 2012, and 2015; and Direct3D 9. If you have a few Steam games, chances are these are already installed, otherwise you can get them all at once with [this program](http://github.com/TASVideos/BizHawk-Prereqs/releases). + +BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive, as long as the prerequisites are installed when you go to run it. + +Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). + +## Installing — GNU+Linux and macOS + +Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). + +[![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) +[![CentOS | bizhawk](https://img.shields.io/badge/CentOS-bizhawk-%23941D7A.svg?logo=centos&style=popout)](https://example.com/bizhawk) +[![Debian (Launchpad) | bizhawk](https://img.shields.io/badge/Debian_(Launchpad)-bizhawk-%23A81D33.svg?logo=debian&style=popout)](https://example.com/bizhawk) +[![elementaryOS (Launchpad) | bizhawk](https://img.shields.io/badge/elementaryOS-bizhawk-%2364BAFF.svg?logo=elementary&style=popout)](https://example.com/bizhawk) +[![Fedora | bizhawk](https://img.shields.io/badge/Fedora-bizhawk-%23294172.svg?logo=fedora&style=popout)](https://example.com/bizhawk) +[![Gentoo | bizhawk](https://img.shields.io/badge/Gentoo-bizhawk-%234E4371.svg?logo=gentoo&style=popout)](https://example.com/bizhawk) +[![Hyperbola | bizhawk](https://img.shields.io/badge/Hyperbola-bizhawk-black.svg?logo=hyperbola&style=popout)](https://example.com/bizhawk) +[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=linux-mint&style=popout)](https://example.com/bizhawk) +[![macOS (Homebrew) | bizhawk](https://img.shields.io/badge/macOS_(Homebrew)-bizhawk-%23999999.svg?logo=apple&style=popout)](https://example.com/bizhawk) +[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=manjaro&style=popout)](https://aur.archlinux.org/packages/bizhawk) +[![MX Linux | bizhawk](https://img.shields.io/badge/MX_Linux-bizhawk-%23506E88.svg?logo=mx-linux&style=popout)](https://example.com/bizhawk) +[![NixOS | bizhawk](https://img.shields.io/badge/NixOS-bizhawk-%234F73BC.svg?colorA=7EB5E0&logo=nixos&style=popout)](https://example.com/bizhawk) +[![openSUSE | bizhawk](https://img.shields.io/badge/openSUSE-bizhawk-%236DA741.svg?logo=opensuse&style=popout)](https://example.com/bizhawk) +[![Solus | bizhawk](https://img.shields.io/badge/Solus-bizhawk-%235294E2.svg?colorA=4C5164&logo=solus&style=popout)](https://example.com/bizhawk) +[![SteamOS (Launchpad) | bizhawk](https://img.shields.io/badge/SteamOS-bizhawk-%231B2838.svg?logo=steam&logoColor=1B2838&style=popout)](https://example.com/bizhawk) +[![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) + +Is your distro not there? Released binaries can be found right here on GitHub: + +[![Misc. Linux | binaries](https://img.shields.io/badge/Misc._Linux-binaries-%23FCC624.svg?logo=linux&logoColor=black&style=popout)](http://github.com/TASVideos/BizHawk/releases) + +If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths - you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). + +Linux distros are supported if the distributor is still supporting your version, you're using Linux 4.4/4.9/4.14/4.19 LTS or 4.20, and there are no updates available in your package manager. *Please* update and reboot. + +macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. + +## Building + +If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download the single listed file (it's compressed as .zip). + +If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as `bizhawk`. This will build and install from the `master` branch here on GitHub. + +### GNU+Linux and macOS + +TODO + +### Windows 7/8.1/10 + +TODO + +## Usage and troubleshooting (casual) + +TODO + +## Usage (TASing or romhacking) + +TODO + +## License + +TODO + +## junk [Here](http://tasvideos.org/Bizhawk/Features.html) is a list of features offered by bizhawk. -## Download Binaries - -Windows users, don't forget to run the [prereq installer](http://github.com/TASVideos/BizHawk-Prereqs/releases) first! - -Release binaries can be found on [on github](http://github.com/TASVideos/BizHawk/releases) - -[Developer build](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/build/artifacts) of the most recent commit - -Never mix different versions of BizHawk. Keep each version in its own folder. - -## Supported Systems - * Nintendo Entertainment System / Famicom / Famicom Disk System (NES/FDS) * Super Nintendo (SNES) * Nintendo 64 @@ -38,8 +99,6 @@ Never mix different versions of BizHawk. Keep each version in its own folder. * Commodore 64 * Sinclair ZX Spectrum -## Resources - [BizHawk homepage](http://tasvideos.org/Bizhawk.html) [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) - Frequently Asked Questions / Troubleshooting From a53f1f97dc014fae82fc58cff88b9d38d3e1de9c Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 8 Jan 2019 16:37:17 +1000 Subject: [PATCH 039/440] draft 2 --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 18ec806b05..9256672fce 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Click `BizHawk-.zip` to download it. Also note the changelog, the full Before you start (by running `EmuHawk.exe`), make sure you have the Windows-only prerequisites installed: .NET Framework 4.6.1; Visual C++ 2010 SP1, 2012, and 2015; and Direct3D 9. If you have a few Steam games, chances are these are already installed, otherwise you can get them all at once with [this program](http://github.com/TASVideos/BizHawk-Prereqs/releases). -BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive, as long as the prerequisites are installed when you go to run it. +BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive, as long as you keep all the files together and the prerequisites are installed when you go to run it. Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). @@ -39,11 +39,13 @@ Install BizHawk with your distro's package manager. The package name is given on [![SteamOS (Launchpad) | bizhawk](https://img.shields.io/badge/SteamOS-bizhawk-%231B2838.svg?logo=steam&logoColor=1B2838&style=popout)](https://example.com/bizhawk) [![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) -Is your distro not there? Released binaries can be found right here on GitHub: +If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). + +Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): [![Misc. Linux | binaries](https://img.shields.io/badge/Misc._Linux-binaries-%23FCC624.svg?logo=linux&logoColor=black&style=popout)](http://github.com/TASVideos/BizHawk/releases) -If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths - you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). +If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). Linux distros are supported if the distributor is still supporting your version, you're using Linux 4.4/4.9/4.14/4.19 LTS or 4.20, and there are no updates available in your package manager. *Please* update and reboot. @@ -51,13 +53,28 @@ macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to ## Building -If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download the single listed file (it's compressed as .zip). +If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download `BizHawk_Developer--#.zip`. -If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as `bizhawk`. This will build and install from the `master` branch here on GitHub. +If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as the main package. If it's available, installing it will automate the build process. ### GNU+Linux and macOS -TODO +*Compiling* requires MSBuild and *running* requires Mono and WINE, but **BizHawk does not run under WINE** — only the bundled libraries are required. + +Building is as easy as: +```sh +git clone https://github.com/TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master +# or ssh: git clone git@github.com:TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master +msbuild BizHawk.sln +``` + +Running is even easier, just execute `EmuHawkMono.sh` in the repo's `output` folder (this folder is what gets distributed in a Release build, you can move/rename it). + +If your distro isn't listed under *Installing* above, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). + +Again, if your distro isn't listed above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). + +Otherwise, see the *Installing* section above. ### Windows 7/8.1/10 From b7f2363584f6b6a647d0bb8912225d891ddc7544 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 8 Jan 2019 11:53:27 +0000 Subject: [PATCH 040/440] EmuHawk: Change deterministic back to how it was before. TRUE if a movie is queued, FALSE if not (and let the cores manage this setting further down the foodchain if they want to). Without this, mGBA skipbios will never work #1432 --- BizHawk.Client.EmuHawk/MainForm.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 28f0311d31..6693e69650 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3594,25 +3594,18 @@ namespace BizHawk.Client.EmuHawk if (args.Deterministic == null) { - // force deterministic in this case - // this is usually null for most cores - // previously this was getting set to false if a movie was not queued for recording - surely that can't be good.. - deterministic = true; - } + // movies should require deterministic emulation in ALL cases + // if the core is managing its own DE through SyncSettings a 'deterministic' bool can be passed into the core's constructor + // it is then up to the core itself to override its own local DeterministicEmulation setting + // if a movie is *not* queued then make this false (this is needed for mGBA logic and is how things were working before I changed them -Asni) + deterministic = Global.MovieSession.QueuedMovie != null; + } else { // a value was actually supplied somehow - use this deterministic = args.Deterministic.Value; } - if (Global.MovieSession.QueuedMovie != null) - { - // movies should require deterministic emulation in ALL cases - // if the core is managing its own DE through SyncSettings a 'deterministic' bool should be passed into the core's constructor - // it is then up to the core itself to override its own local DeterministicEmulation setting - deterministic = true; - } - if (!GlobalWin.Tools.AskSave()) { return false; From a6b371727197a85ef625aeb7443080d271472f5f Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 8 Jan 2019 21:56:04 +1000 Subject: [PATCH 041/440] draft 3 --- README.md | 112 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 9256672fce..6fe249b572 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,41 @@ BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as fullscreen, rewind, and joypad support in addition to rerecording and debugging tools for all system cores. +## Core feature matrix + +Most games for every system in the table will run perfectly, and every system supports fast-forward, frame advance, and rewind. + +System | Play+FF/ADV/RW | Debugging | (Input) Recording +--:|:-:|:-:|:-: +Apple II | ✓ | ? | ? +Atari 2600 | ✓ | ? | ? +Atari 7800 | ✓ | ? | ? +Atari Lynx | ✓ | ? | ? +ColecoVision | ✓ | ? | ? +Commodore 64 | ✓ | ? | ? +Game Boy / GBC | ✓ | ? | ? +GBA | ✓ | ? | ? +Genesis | ✓ | ? | ? +IntelliVision | ✓ | ? | ? +Master System | ✓ | ? | ? +N64 | ✓ | ? | ? +Neo Geo Pocket | ✓ | ? | ? +NES | ✓ | ? | ? +PSX | ✓ | ? | ? +Saturn | ✓ | ? | ? +SNES | ✓ | ? | ? +TI-83 | ✓ | ? | ? +TurboGrafx-16 | ✓ | ? | ? +Virtual Boy | ✓ | ? | ? +WonderSwan | ✓ | ? | ? +ZX Spectrum | ✓ | ? | ? + +EmuHawk's frontend also has a comprehensive input mapper, with keyboard and controller support (even simultaneously), hotkeys, and turbo/rapid fire. + +In addition to input recording (with TAStudio), you can also record the emulated system's audio and video, either of your own gameplay or of a prerecorded movie (TAS). See the *Usage (advanced)* section below for more info about the many debugging and recording features. + +Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. + ## Installing — Windows 7/8.1/10 Released binaries can be found right here on GitHub: @@ -74,57 +109,54 @@ If your distro isn't listed under *Installing* above, you might get an "Unknown Again, if your distro isn't listed above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -Otherwise, see the *Installing* section above. +Once built, see the *Installing* section above. ### Windows 7/8.1/10 TODO -## Usage and troubleshooting (casual) +[Compiling](http://tasvideos.org/Bizhawk/Compiling.html) + +## Usage (casual) TODO -## Usage (TASing or romhacking) +## Usage (advanced) TODO +[Commandline](http://tasvideos.org/Bizhawk/CommandLine.html) + +[CompactDiscInfoDump](http://tasvideos.org/Bizhawk/CompactDiscInfoDump.html) + +[Rerecording](http://tasvideos.org/Bizhawk/Rerecording.html) + +[TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) + +## Troubleshooting and support + +TODO + +[BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) + +[BizHawk wiki](http://tasvideos.org/Bizhawk.html) + +[FAQ](http://tasvideos.org/Bizhawk/FAQ.html) + +## Contributing + +BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the MIT license, this is *optional*, just be careful with reusing cores as some have copyleft licenses. + +If you've already made changes, the best way to contribute is with a Pull Request here on GitHub. If you're looking for something to do, check the issue tracker here on GitHub: + +[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/issues) + +It's a good idea to check if anyone else is working on an issue by asking on IRC: + +[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-black.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) +[![Matrix (via bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(via_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-black.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) + ## License TODO - -## junk - -[Here](http://tasvideos.org/Bizhawk/Features.html) is a list of features offered by bizhawk. - - * Nintendo Entertainment System / Famicom / Famicom Disk System (NES/FDS) - * Super Nintendo (SNES) - * Nintendo 64 - * Game Boy, Game Boy Color, and Super Game Boy - * Game Boy Advance - * Sony PlayStation - * Sega Master System, Game Gear, and SG-1000 - * Sega Genesis / Sega-CD - * Sega Saturn - * PC-Engine (TurboGrafx-16) / CD-ROM & SuperGrafx - * Atari 2600 - * Atari 7800 - * Atari Lynx - * ColecoVision - * TI-83 Calculator - * Wonderswan and Wonderswan Color - * Apple II - * Commodore 64 - * Sinclair ZX Spectrum - -[BizHawk homepage](http://tasvideos.org/Bizhawk.html) - -[FAQ](http://tasvideos.org/Bizhawk/FAQ.html) - Frequently Asked Questions / Troubleshooting - -[Compiling](http://tasvideos.org/Bizhawk/Compiling.html) - What is needed to compile BizHawk src - -[CompactDiscInfoDump](http://tasvideos.org/Bizhawk/CompactDiscInfoDump.html) - A concise explanation of compact disc CDs, gathered for the first time EVER in one location, and mostly inaccurate - -[Rerecording](http://tasvideos.org/Bizhawk/Rerecording.html) - (Work in progress) - Documentation of the rerecording implementation of BizHawk - * [TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) - Mnemonic patterns for each platform for .tas (input) files. - -[Commandline](http://tasvideos.org/Bizhawk/CommandLine.html) - Documentation of the command line options in BizHawk From 4c5728dedb36e14cef9b224bd43827997eff05e1 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 8 Jan 2019 12:48:40 +0000 Subject: [PATCH 042/440] EmuHawk: Deterministic Emulation Revert --- BizHawk.Client.EmuHawk/MainForm.cs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 6693e69650..78a1fa21bd 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3589,23 +3589,12 @@ namespace BizHawk.Client.EmuHawk } try - { - bool deterministic; - - if (args.Deterministic == null) - { - // movies should require deterministic emulation in ALL cases - // if the core is managing its own DE through SyncSettings a 'deterministic' bool can be passed into the core's constructor - // it is then up to the core itself to override its own local DeterministicEmulation setting - // if a movie is *not* queued then make this false (this is needed for mGBA logic and is how things were working before I changed them -Asni) - deterministic = Global.MovieSession.QueuedMovie != null; - } - else - { - // a value was actually supplied somehow - use this - deterministic = args.Deterministic.Value; - } - + { + // movies should require deterministic emulation in ALL cases + // if the core is managing its own DE through SyncSettings a 'deterministic' bool can be passed into the core's constructor + // it is then up to the core itself to override its own local DeterministicEmulation setting + bool deterministic = args.Deterministic ?? Global.MovieSession.QueuedMovie != null; + if (!GlobalWin.Tools.AskSave()) { return false; From 47064f3d21bc9a727bcacb7a73119a6695dd39f7 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 03:52:51 +1000 Subject: [PATCH 043/440] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6fe249b572..8974b9173f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/releases/latest) ![Unique systems emulated | 22](https://img.shields.io/badge/Unique_systems_emulated-22-darkgreen.svg?style=flat) BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as fullscreen, rewind, and joypad support in addition to rerecording and debugging tools for all system cores. @@ -43,11 +43,11 @@ Most of the frontend can be controlled with Lua scripts (only on Windows for now Released binaries can be found right here on GitHub: -[![Windows | binaries](https://img.shields.io/badge/Windows-binaries-%230078D6.svg?logo=windows&logoColor=0078D6&style=popout)](http://github.com/TASVideos/BizHawk/releases) +[![Windows | binaries](https://img.shields.io/badge/Windows-binaries-%230078D6.svg?logo=windows&logoColor=0078D6&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) Click `BizHawk-.zip` to download it. Also note the changelog, the full version of which is [on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix different versions** of BizHawk, keep each version in its own folder. -Before you start (by running `EmuHawk.exe`), make sure you have the Windows-only prerequisites installed: .NET Framework 4.6.1; Visual C++ 2010 SP1, 2012, and 2015; and Direct3D 9. If you have a few Steam games, chances are these are already installed, otherwise you can get them all at once with [this program](http://github.com/TASVideos/BizHawk-Prereqs/releases). +Before you start (by running `EmuHawk.exe`), make sure you have the Windows-only prerequisites installed: .NET Framework 4.6.1; Visual C++ 2010 SP1, 2012, and 2015; and Direct3D 9. If you have a few Steam games, chances are these are already installed, otherwise you can get them all at once with [this program](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive, as long as you keep all the files together and the prerequisites are installed when you go to run it. @@ -78,7 +78,7 @@ If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` do Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): -[![Misc. Linux | binaries](https://img.shields.io/badge/Misc._Linux-binaries-%23FCC624.svg?logo=linux&logoColor=black&style=popout)](http://github.com/TASVideos/BizHawk/releases) +[![Misc. Linux | binaries](https://img.shields.io/badge/Misc._Linux-binaries-%23FCC624.svg?logo=linux&logoColor=black&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). From 689eb388018942fb0969bca573a73b28e6c57359 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 03:57:51 +1000 Subject: [PATCH 044/440] Copy blurb from GitLab mirror --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8974b9173f..11f858ae01 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/releases/latest) ![Unique systems emulated | 22](https://img.shields.io/badge/Unique_systems_emulated-22-darkgreen.svg?style=flat) -BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as fullscreen, rewind, and joypad support in addition to rerecording and debugging tools for all system cores. +A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). ## Core feature matrix From 0005b938e0a632e55d153a4cb0e4479e391e88f2 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 15:53:31 +1000 Subject: [PATCH 045/440] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 11f858ae01..e3a26c0df7 100644 --- a/README.md +++ b/README.md @@ -154,9 +154,14 @@ If you've already made changes, the best way to contribute is with a Pull Reques It's a good idea to check if anyone else is working on an issue by asking on IRC: [![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-black.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) -[![Matrix (via bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(via_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-black.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +And of course, open a "feature request" issue before adding features. No point making something that no-one's going to use. + ## License -TODO +From the [full text](https://github.com/TASVideos/BizHawk/blob/master/LICENSE): +> This repository contains original work chiefly in c# by the BizHawk team (which is all provided under the MIT License), embedded submodules from other authors with their own licenses clearly provided, other embedded submodules from other authors WITHOUT their own licenses clearly provided, customizations by the BizHawk team to many of those submodules (which is provided under the MIT license), and compiled binary executable modules from other authors without their licenses OR their origins clearly indicated. + +In short, the frontend is MIT, and past that you're on your own. From a43eacaa40a8e7173504d040df40a7cec2b5105d Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 15:54:24 +1000 Subject: [PATCH 046/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3a26c0df7..d367efc523 100644 --- a/README.md +++ b/README.md @@ -164,4 +164,4 @@ And of course, open a "feature request" issue before adding features. No point m From the [full text](https://github.com/TASVideos/BizHawk/blob/master/LICENSE): > This repository contains original work chiefly in c# by the BizHawk team (which is all provided under the MIT License), embedded submodules from other authors with their own licenses clearly provided, other embedded submodules from other authors WITHOUT their own licenses clearly provided, customizations by the BizHawk team to many of those submodules (which is provided under the MIT license), and compiled binary executable modules from other authors without their licenses OR their origins clearly indicated. -In short, the frontend is MIT, and past that you're on your own. +In short, the frontend is MIT (Expat), beyond that you're on your own. From 220e0612a9d25ac964e8a721d5d9bf598a450ad1 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 15:58:16 +1000 Subject: [PATCH 047/440] Update README.md --- README.md | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d367efc523..3538a319db 100644 --- a/README.md +++ b/README.md @@ -135,13 +135,11 @@ TODO ## Troubleshooting and support -TODO +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: -[BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) - -[BizHawk wiki](http://tasvideos.org/Bizhawk.html) - -[FAQ](http://tasvideos.org/Bizhawk/FAQ.html) +[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-black.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) +[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-black.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) ## Contributing @@ -151,13 +149,7 @@ If you've already made changes, the best way to contribute is with a Pull Reques [![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/issues) -It's a good idea to check if anyone else is working on an issue by asking on IRC: - -[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-black.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) -[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-black.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) - -And of course, open a "feature request" issue before adding features. No point making something that no-one's going to use. +It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). And of course, open a "feature request" issue before adding features. No point making something that no-one's going to use. ## License From ff19a708a42a18d70a7ca0f8160dbc953ec15ad4 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 16:11:27 +1000 Subject: [PATCH 048/440] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3538a319db..64b37f7cf8 100644 --- a/README.md +++ b/README.md @@ -137,9 +137,9 @@ TODO A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: -[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-black.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) -[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-black.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-black.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) +[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) ## Contributing From 10d7bcee6e9085e4ace71eba65a4302eec05d267 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 16:21:12 +1000 Subject: [PATCH 049/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64b37f7cf8..65bba1c5ba 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ TODO [TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) -## Troubleshooting and support +## Support and troubleshooting A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: From d8c22b5c9ea007424a4c58b8f8e2d1ea3c08e95f Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 16:23:16 +1000 Subject: [PATCH 050/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65bba1c5ba..485e736806 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ TODO ## Support and troubleshooting -A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: [![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) From bafcd6c7240dcca5f5fd5da4de718bad77b6c2fa Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 20:27:28 +1000 Subject: [PATCH 051/440] Update README.md --- README.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 485e736806..449eba295f 100644 --- a/README.md +++ b/README.md @@ -58,22 +58,12 @@ Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported f Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). [![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) -[![CentOS | bizhawk](https://img.shields.io/badge/CentOS-bizhawk-%23941D7A.svg?logo=centos&style=popout)](https://example.com/bizhawk) -[![Debian (Launchpad) | bizhawk](https://img.shields.io/badge/Debian_(Launchpad)-bizhawk-%23A81D33.svg?logo=debian&style=popout)](https://example.com/bizhawk) -[![elementaryOS (Launchpad) | bizhawk](https://img.shields.io/badge/elementaryOS-bizhawk-%2364BAFF.svg?logo=elementary&style=popout)](https://example.com/bizhawk) -[![Fedora | bizhawk](https://img.shields.io/badge/Fedora-bizhawk-%23294172.svg?logo=fedora&style=popout)](https://example.com/bizhawk) -[![Gentoo | bizhawk](https://img.shields.io/badge/Gentoo-bizhawk-%234E4371.svg?logo=gentoo&style=popout)](https://example.com/bizhawk) -[![Hyperbola | bizhawk](https://img.shields.io/badge/Hyperbola-bizhawk-black.svg?logo=hyperbola&style=popout)](https://example.com/bizhawk) -[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=linux-mint&style=popout)](https://example.com/bizhawk) [![macOS (Homebrew) | bizhawk](https://img.shields.io/badge/macOS_(Homebrew)-bizhawk-%23999999.svg?logo=apple&style=popout)](https://example.com/bizhawk) -[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=manjaro&style=popout)](https://aur.archlinux.org/packages/bizhawk) -[![MX Linux | bizhawk](https://img.shields.io/badge/MX_Linux-bizhawk-%23506E88.svg?logo=mx-linux&style=popout)](https://example.com/bizhawk) -[![NixOS | bizhawk](https://img.shields.io/badge/NixOS-bizhawk-%234F73BC.svg?colorA=7EB5E0&logo=nixos&style=popout)](https://example.com/bizhawk) -[![openSUSE | bizhawk](https://img.shields.io/badge/openSUSE-bizhawk-%236DA741.svg?logo=opensuse&style=popout)](https://example.com/bizhawk) -[![Solus | bizhawk](https://img.shields.io/badge/Solus-bizhawk-%235294E2.svg?colorA=4C5164&logo=solus&style=popout)](https://example.com/bizhawk) -[![SteamOS (Launchpad) | bizhawk](https://img.shields.io/badge/SteamOS-bizhawk-%231B2838.svg?logo=steam&logoColor=1B2838&style=popout)](https://example.com/bizhawk) [![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) +[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=linux-mint&style=popout)](https://example.com/bizhawk) +[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=manjaro&style=popout)](https://aur.archlinux.org/packages/bizhawk) + If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): From 8557cdb90aae12d45bb17f32e6d8e9661ea0c226 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 20:44:11 +1000 Subject: [PATCH 052/440] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 449eba295f..0ace764534 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,11 @@ Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported f Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). [![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) +[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=data:image/png;base64,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&style=popout)](https://example.com/bizhawk) [![macOS (Homebrew) | bizhawk](https://img.shields.io/badge/macOS_(Homebrew)-bizhawk-%23999999.svg?logo=apple&style=popout)](https://example.com/bizhawk) +[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABRUlEQVR4nO3bQUrDQBTG8Qdu3dS91r2CAzYE3Cm9QBURmjq7Yk9QIsELJYJ2XYqh7UJbL9NcYFyoGAQZiFMygf8Hb/vNm192IREhhJBS+ou4Fa3vM71Kitv3B1P3lHer2qFXSTFYJ2l/EbesANev46y7HJkw1yZ4GdQ+5d2qdoS5Nt3lyNy8xakV4Hw+LOq+tGuA77mY322sAL48+W0AhLk2f93b2SE+A/zuAwAAAAAAAAAAAAAAAAAAcH3IqcNpJMBWAkATAVy+E2wkgE9dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAZzrTaOPT0i67OtPI/suMyq6efVraZdfJ4+WTFWD3bP9Ypb1JMIsq/zzlHcAsKlTam+wFB0dWABHZEZFDEVHi4NO2f3S47FIi0v66GyHkJx/0rGTAdYdsEwAAAABJRU5ErkJggg==&style=popout)](https://aur.archlinux.org/packages/bizhawk) [![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) -[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=linux-mint&style=popout)](https://example.com/bizhawk) -[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=manjaro&style=popout)](https://aur.archlinux.org/packages/bizhawk) - If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): From a0d9c8133101fb722975b2a0cfed9e352bea1bf5 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 00:31:48 +1000 Subject: [PATCH 053/440] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ace764534..337eee1031 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported f Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). [![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) +[![Debian (Launchpad) | bizhawk](https://img.shields.io/badge/Debian_(Launchpad)-bizhawk-%23A81D33.svg?logo=debian&style=popout)](https://example.com/bizhawk) [![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=data:image/png;base64,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&style=popout)](https://example.com/bizhawk) [![macOS (Homebrew) | bizhawk](https://img.shields.io/badge/macOS_(Homebrew)-bizhawk-%23999999.svg?logo=apple&style=popout)](https://example.com/bizhawk) [![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABRUlEQVR4nO3bQUrDQBTG8Qdu3dS91r2CAzYE3Cm9QBURmjq7Yk9QIsELJYJ2XYqh7UJbL9NcYFyoGAQZiFMygf8Hb/vNm192IREhhJBS+ou4Fa3vM71Kitv3B1P3lHer2qFXSTFYJ2l/EbesANev46y7HJkw1yZ4GdQ+5d2qdoS5Nt3lyNy8xakV4Hw+LOq+tGuA77mY322sAL48+W0AhLk2f93b2SE+A/zuAwAAAAAAAAAAAAAAAAAAcH3IqcNpJMBWAkATAVy+E2wkgE9dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAZzrTaOPT0i67OtPI/suMyq6efVraZdfJ4+WTFWD3bP9Ypb1JMIsq/zzlHcAsKlTam+wFB0dWABHZEZFDEVHi4NO2f3S47FIi0v66GyHkJx/0rGTAdYdsEwAAAABJRU5ErkJggg==&style=popout)](https://aur.archlinux.org/packages/bizhawk) From c2bc9893e5b5a34523c4cc1e6946ef6265fdc541 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 9 Jan 2019 14:37:11 +0000 Subject: [PATCH 054/440] Add Debian as option in EmuHawkMono.sh runscript --- Assets/EmuHawkMono.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/EmuHawkMono.sh b/Assets/EmuHawkMono.sh index 45298de879..68dad15c38 100755 --- a/Assets/EmuHawkMono.sh +++ b/Assets/EmuHawkMono.sh @@ -9,6 +9,7 @@ if [ "$(command -v lsb_release)" ]; then case "$(lsb_release -i | cut -c17- | tr -d "\n")" in "Arch"|"ManjaroLinux") libpath="/usr/lib/wine";; "Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";; + "Debian"|"DebianLinux") libpath="/usr/lib/x86_64-linux-gnu/wine";; esac fi if [ -z "$libpath" ]; then From 31300b9ccab3bc8c3220dd3a49552ae2ecd4eb26 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 01:35:01 +1000 Subject: [PATCH 055/440] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 337eee1031..4316c3df24 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,13 @@ Building is as easy as: ```sh git clone https://github.com/TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master # or ssh: git clone git@github.com:TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master -msbuild BizHawk.sln +msbuild --release BizHawk.sln ``` +Remove the `--release` flag from MSBuild if you want debugging symbols. + +TODO it's not --release + Running is even easier, just execute `EmuHawkMono.sh` in the repo's `output` folder (this folder is what gets distributed in a Release build, you can move/rename it). If your distro isn't listed under *Installing* above, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). From fe52089b1af91507d1dcef386c1d494e245ea0eb Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 01:37:09 +1000 Subject: [PATCH 056/440] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4316c3df24..6d143e9780 100644 --- a/README.md +++ b/README.md @@ -97,13 +97,9 @@ Remove the `--release` flag from MSBuild if you want debugging symbols. TODO it's not --release -Running is even easier, just execute `EmuHawkMono.sh` in the repo's `output` folder (this folder is what gets distributed in a Release build, you can move/rename it). +If your distro isn't listed above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -If your distro isn't listed under *Installing* above, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). - -Again, if your distro isn't listed above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). - -Once built, see the *Installing* section above. +Once built, see the *Installing* section above, substituting the repo's `output` folder for the download. If your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). ### Windows 7/8.1/10 From 5297ba8eb78e7dda473b7506ff864208993091c0 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 01:46:32 +1000 Subject: [PATCH 057/440] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6d143e9780..0100b3349b 100644 --- a/README.md +++ b/README.md @@ -90,16 +90,16 @@ Building is as easy as: ```sh git clone https://github.com/TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master # or ssh: git clone git@github.com:TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master -msbuild --release BizHawk.sln +msbuild /p:Configuration=Release BizHawk.sln ``` -Remove the `--release` flag from MSBuild if you want debugging symbols. +Remove the `/p:...` flag from MSBuild if you want debugging symbols. -TODO it's not --release +If your distro isn't listed under *Installing* above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -If your distro isn't listed above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). +Once built, see the *Installing* section, substituting the repo's `output` folder for the download. -Once built, see the *Installing* section above, substituting the repo's `output` folder for the download. If your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). +Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). ### Windows 7/8.1/10 From 245dce55712d8bf9436a9b33a5f05e6b9c3aefab Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:04:45 +0000 Subject: [PATCH 058/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0100b3349b..aababd758e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). +tl;dr: click the "latest" button above to grab it. The changelog is [here on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). + ## Core feature matrix Most games for every system in the table will run perfectly, and every system supports fast-forward, frame advance, and rewind. From 592c6cd9456c474bea8b808e00383404a34d4654 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:05:57 +0000 Subject: [PATCH 059/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aababd758e..e49a7d7a5c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -tl;dr: click the "latest" button above to grab it. The changelog is [here on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). +tl;dr: click the "latest" button above to grab it. The changelog is [here on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix versions**, copy `config.ini` to keep settings. ## Core feature matrix From 49301f4fe0e426f9116ae6bdf92dc9547c414535 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:09:28 +0000 Subject: [PATCH 060/440] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e49a7d7a5c..35bf9e96dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/releases/latest) ![Unique systems emulated | 22](https://img.shields.io/badge/Unique_systems_emulated-22-darkgreen.svg?style=flat) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?style=flat)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?style=flat) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). @@ -84,6 +84,12 @@ If you want to test the latest changes without building BizHawk yourself, grab t If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as the main package. If it's available, installing it will automate the build process. +### Windows 7/8.1/10 + +TODO + +[Compiling](http://tasvideos.org/Bizhawk/Compiling.html) + ### GNU+Linux and macOS *Compiling* requires MSBuild and *running* requires Mono and WINE, but **BizHawk does not run under WINE** — only the bundled libraries are required. @@ -103,12 +109,6 @@ Once built, see the *Installing* section, substituting the repo's `output` folde Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). -### Windows 7/8.1/10 - -TODO - -[Compiling](http://tasvideos.org/Bizhawk/Compiling.html) - ## Usage (casual) TODO From 233ac59d8a914dd57bd6f2ace48e520a23c15c70 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:14:16 +0000 Subject: [PATCH 061/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35bf9e96dc..741b315516 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Linux distros are supported if the distributor is still supporting your version, macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. -## Building +## Building/Testing If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download `BizHawk_Developer--#.zip`. From 65ce6409ab3bea5023528ccc56cdbd502b7c9ccc Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:18:41 +0000 Subject: [PATCH 062/440] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 741b315516..fce0c411d0 100644 --- a/README.md +++ b/README.md @@ -137,11 +137,13 @@ A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the MIT license, this is *optional*, just be careful with reusing cores as some have copyleft licenses. -If you've already made changes, the best way to contribute is with a Pull Request here on GitHub. If you're looking for something to do, check the issue tracker here on GitHub: +If you'd like to fix bugs, check the issue tracker here on GitHub: [![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/issues) -It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). And of course, open a "feature request" issue before adding features. No point making something that no-one's going to use. +It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). + +If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. ## License From 43686a2cf173786f450996aa43ea4cb5e7b5d122 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:24:20 +0000 Subject: [PATCH 063/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fce0c411d0..12a0043134 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,8 @@ A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). + ## Contributing BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the MIT license, this is *optional*, just be careful with reusing cores as some have copyleft licenses. From 37eb3a41fdb86f124955a82dc48b89bf44ebfb58 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:31:16 +0000 Subject: [PATCH 064/440] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 12a0043134..29c2749017 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,15 @@ Released binaries can be found right here on GitHub: Click `BizHawk-.zip` to download it. Also note the changelog, the full version of which is [on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix different versions** of BizHawk, keep each version in its own folder. -Before you start (by running `EmuHawk.exe`), make sure you have the Windows-only prerequisites installed: .NET Framework 4.6.1; Visual C++ 2010 SP1, 2012, and 2015; and Direct3D 9. If you have a few Steam games, chances are these are already installed, otherwise you can get them all at once with [this program](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). +Before you start (by running `EmuHawk.exe`), you'll need the following Windows-only prerequisites installed. You can get them all at once with [this program](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). +* .NET Framework 4.6.1 +* Visual C++ Redists + * 2010 SP1 + * 2012 + * 2015 +* Direct3D 9 -BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive, as long as you keep all the files together and the prerequisites are installed when you go to run it. +BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive — as long as you keep all the files together, and the prerequisites are installed when you go to run it. Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). From 96042e217426338dcac28895b8de387b6be24dee Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 9 Jan 2019 17:39:13 +0000 Subject: [PATCH 065/440] Update README.md --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 29c2749017..f24feb9b6f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,16 @@ A multi-system emulator written in C#. As well as quality-of-life features for c tl;dr: click the "latest" button above to grab it. The changelog is [here on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix versions**, copy `config.ini` to keep settings. +Jump to: +* [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) +* [Installing — GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--gnulinux-and-macos) +* [Building/Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#buildingtesting) +* [Usage (emulation)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-emulation) +* [Usage (TASing)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-tasing) +* [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) +* [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) +* [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) + ## Core feature matrix Most games for every system in the table will run perfectly, and every system supports fast-forward, frame advance, and rewind. @@ -115,11 +125,11 @@ Once built, see the *Installing* section, substituting the repo's `output` folde Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). -## Usage (casual) +## Usage (emulation) TODO -## Usage (advanced) +## Usage (TASing) TODO From d7caf48a70032cfbc57517cf3fea6804d37444b7 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 9 Jan 2019 17:50:57 +0000 Subject: [PATCH 066/440] EmuHawkMono.sh 'I suck at shell scripts' fix --- Assets/EmuHawkMono.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Assets/EmuHawkMono.sh b/Assets/EmuHawkMono.sh index 68dad15c38..a42a52a5f6 100755 --- a/Assets/EmuHawkMono.sh +++ b/Assets/EmuHawkMono.sh @@ -8,8 +8,7 @@ libpath="" if [ "$(command -v lsb_release)" ]; then case "$(lsb_release -i | cut -c17- | tr -d "\n")" in "Arch"|"ManjaroLinux") libpath="/usr/lib/wine";; - "Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";; - "Debian"|"DebianLinux") libpath="/usr/lib/x86_64-linux-gnu/wine";; + "Debian"|"Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";; esac fi if [ -z "$libpath" ]; then From 531e4d8909fe4eb1223183c3845afba31ba32581 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 04:37:10 +1000 Subject: [PATCH 067/440] Update README.md --- README.md | 62 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index f24feb9b6f..2b99087a1c 100644 --- a/README.md +++ b/README.md @@ -16,40 +16,46 @@ Jump to: * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) -## Core feature matrix +## Features -Most games for every system in the table will run perfectly, and every system supports fast-forward, frame advance, and rewind. +The "core" features, common to every system core, are: +* rom format and region detection and a corruption check +* speed control, including frame stepping and rewinding +* input recording (making TAS movies) +* memory view/search/edit in all parts of the emulated HW +* 10 savestate slots and save/load to file +* more things I can't remember -System | Play+FF/ADV/RW | Debugging | (Input) Recording +System | "Core" Features | Game Coverage† | Peripherals --:|:-:|:-:|:-: -Apple II | ✓ | ? | ? -Atari 2600 | ✓ | ? | ? -Atari 7800 | ✓ | ? | ? -Atari Lynx | ✓ | ? | ? -ColecoVision | ✓ | ? | ? -Commodore 64 | ✓ | ? | ? -Game Boy / GBC | ✓ | ? | ? -GBA | ✓ | ? | ? -Genesis | ✓ | ? | ? -IntelliVision | ✓ | ? | ? -Master System | ✓ | ? | ? -N64 | ✓ | ? | ? -Neo Geo Pocket | ✓ | ? | ? -NES | ✓ | ? | ? -PSX | ✓ | ? | ? -Saturn | ✓ | ? | ? -SNES | ✓ | ? | ? -TI-83 | ✓ | ? | ? -TurboGrafx-16 | ✓ | ? | ? -Virtual Boy | ✓ | ? | ? -WonderSwan | ✓ | ? | ? -ZX Spectrum | ✓ | ? | ? +Apple II | ✓ | 95%? | ? +Atari 2600 | ✓ | 95%? | ? +Atari 7800 | ✓ | 95%? | ? +Atari Lynx | ✓ | 95%? | ? +ColecoVision | ✓ | 95%? | ? +Commodore 64 | ✓ | 95%? | ? +Game Boy / GBC | ✓ | 95%? | ? +GBA | ✓ | 95%? | ? +Genesis | ✓ | 95%? | ? +IntelliVision | ✓ | 95%? | ? +Master System | ✓ | 95%? | ? +N64 | ✓ | 95%? | ? +Neo Geo Pocket | ✓ | 95%? | ? +NES | ✓ | 95%? | ? +PSX | ✓ | 95%? | ? +Saturn | ✓ | 95%? | ? +SNES | ✓ | 95%? | ? +TI-83 | ✓ | 95%? | ? +TurboGrafx-16 | ✓ | 95%? | ? +Virtual Boy | ✓ | 95%? | ? +WonderSwan | ✓ | 95%? | ? +ZX Spectrum | ✓ | 95%? | ? -EmuHawk's frontend also has a comprehensive input mapper, with keyboard and controller support (even simultaneously), hotkeys, and turbo/rapid fire. +† *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) -In addition to input recording (with TAStudio), you can also record the emulated system's audio and video, either of your own gameplay or of a prerecorded movie (TAS). See the *Usage (advanced)* section below for more info about the many debugging and recording features. +EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller with analog support, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. -Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. +See the *Usage* sections below for details about specific tools and config menus. ## Installing — Windows 7/8.1/10 From b29516fb59c0264faf061d3ff20e123bd8efb7dd Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 04:39:40 +1000 Subject: [PATCH 068/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b99087a1c..9ca2cfddc3 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ ZX Spectrum | ✓ | 95%? | ? † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) -EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller with analog support, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. +EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller, analog from analog or from digital, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. See the *Usage* sections below for details about specific tools and config menus. From cc532a2988df07b25300c53271c5e6933238bed4 Mon Sep 17 00:00:00 2001 From: zeromus Date: Wed, 9 Jan 2019 16:20:53 -0500 Subject: [PATCH 069/440] update nlua.dll with one built with optimization --- output/dll/nlua/NLua.dll | Bin 101376 -> 91648 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/output/dll/nlua/NLua.dll b/output/dll/nlua/NLua.dll index 5bdc058e66fb68f7e8d907f08e06b6e4207d9a53..57e6d07cb9c15bbf514d7ad4059c858a998eb1e9 100644 GIT binary patch literal 91648 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 literal 101376 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 J|LY|1zX4x7&!YeU From 41061b44abcaaf0134db84e89bdb84aa054e3fe4 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 14:30:49 +1000 Subject: [PATCH 070/440] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9ca2cfddc3..84e6c0a858 100644 --- a/README.md +++ b/README.md @@ -33,23 +33,23 @@ Atari 2600 | ✓ | 95%? | ? Atari 7800 | ✓ | 95%? | ? Atari Lynx | ✓ | 95%? | ? ColecoVision | ✓ | 95%? | ? -Commodore 64 | ✓ | 95%? | ? -Game Boy / GBC | ✓ | 95%? | ? +Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) +GB/GBC | ✓ | 95%? | ? GBA | ✓ | 95%? | ? -Genesis | ✓ | 95%? | ? +Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) IntelliVision | ✓ | 95%? | ? Master System | ✓ | 95%? | ? -N64 | ✓ | 95%? | ? -Neo Geo Pocket | ✓ | 95%? | ? +N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) +NGP/NGPC | ✓ | 95%? | N/A NES | ✓ | 95%? | ? PSX | ✓ | 95%? | ? Saturn | ✓ | 95%? | ? SNES | ✓ | 95%? | ? -TI-83 | ✓ | 95%? | ? -TurboGrafx-16 | ✓ | 95%? | ? -Virtual Boy | ✓ | 95%? | ? -WonderSwan | ✓ | 95%? | ? -ZX Spectrum | ✓ | 95%? | ? +TI-83 | ✓ | 95%? | N/A +PC Engine / SG | ✓ | 95%? | ? +Virtual Boy | ✓ | 95%? | N/A +WonderSwan | ✓ | 95%? | N/A +ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) From 0a41092150a2823f7d2231d6fa81c872d8b992c8 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 15:01:37 +1000 Subject: [PATCH 071/440] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 84e6c0a858..adeb2ab38a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Jump to: * [Usage (TASing)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-tasing) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) +* [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) ## Features @@ -169,6 +170,15 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. +## Related projects + +* [DeSmuME](https://desmume.org) for DS/Lite — cross-platform +* [Dolphin](https://dolphin-emu.org) for GameCube and (original) Wii — cross-platform +* [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run on Unix +* [Hourglass](https://github.com/TASVideos/hourglass-win32) for Windows Win32 — Windows-only, see also [rewrite project](https://github.com/Hourglass-Resurrection/Hourglass-Resurrection) +* [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only +* [openMSX](https://openmsx.org) for MSX — cross-platform + ## License From the [full text](https://github.com/TASVideos/BizHawk/blob/master/LICENSE): From 7ab651786736565f428b6268685a0f569c0a3262 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 20:28:43 +1000 Subject: [PATCH 072/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index adeb2ab38a..bef2f76dc8 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) -EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller, analog from analog or from digital, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. +EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller, analog from digital and digital from analog, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. See the *Usage* sections below for details about specific tools and config menus. From 041436e5fdeee66ee47d464f80128a5e4d160248 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 20:42:06 +1000 Subject: [PATCH 073/440] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bef2f76dc8..4fe84ecb88 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?style=flat)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?style=flat) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?style=popout) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). @@ -152,9 +152,9 @@ TODO A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: -[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) -[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=popout)](ircs://chat.freenode.net:6697/bizhawk) +[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=popout)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=popout)](http://webchat.freenode.net/?channels=bizhawk) If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). @@ -164,7 +164,7 @@ BizHawk is Open Source Software, so you're free to modify it however you please, If you'd like to fix bugs, check the issue tracker here on GitHub: -[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=flat)](https://github.com/TASVideos/BizHawk/issues) +[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/issues) It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). From b82875f33aa67f2f2fa04ec8daaf836fbe8a926c Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 20:50:32 +1000 Subject: [PATCH 074/440] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4fe84ecb88..e6c93191ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?style=popout) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=white&style=popout) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). @@ -152,9 +152,9 @@ TODO A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: -[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=popout)](ircs://chat.freenode.net:6697/bizhawk) -[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=popout)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=popout)](http://webchat.freenode.net/?channels=bizhawk) +[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) +[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From ef002869fb5a386fd79f4ea4ae146860dd1f0979 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 21:11:26 +1000 Subject: [PATCH 075/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6c93191ef..fbcec8430f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=white&style=popout) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). @@ -164,7 +164,7 @@ BizHawk is Open Source Software, so you're free to modify it however you please, If you'd like to fix bugs, check the issue tracker here on GitHub: -[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&style=popout)](https://github.com/TASVideos/BizHawk/issues) +[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). From 9155d213d312f4841a50139363b2a10e36840b4c Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 23:50:46 +1000 Subject: [PATCH 076/440] Update README.md --- README.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index fbcec8430f..cd4b382c0c 100644 --- a/README.md +++ b/README.md @@ -27,30 +27,30 @@ The "core" features, common to every system core, are: * 10 savestate slots and save/load to file * more things I can't remember -System | "Core" Features | Game Coverage† | Peripherals ---:|:-:|:-:|:-: -Apple II | ✓ | 95%? | ? -Atari 2600 | ✓ | 95%? | ? -Atari 7800 | ✓ | 95%? | ? -Atari Lynx | ✓ | 95%? | ? -ColecoVision | ✓ | 95%? | ? -Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) -GB/GBC | ✓ | 95%? | ? -GBA | ✓ | 95%? | ? -Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) -IntelliVision | ✓ | 95%? | ? -Master System | ✓ | 95%? | ? -N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) -NGP/NGPC | ✓ | 95%? | N/A -NES | ✓ | 95%? | ? -PSX | ✓ | 95%? | ? -Saturn | ✓ | 95%? | ? -SNES | ✓ | 95%? | ? -TI-83 | ✓ | 95%? | N/A -PC Engine / SG | ✓ | 95%? | ? -Virtual Boy | ✓ | 95%? | N/A -WonderSwan | ✓ | 95%? | N/A -ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) +System | "Core" Features | Game Coverage† | Peripherals | Debugging +--:|:-:|:-:|:-:|:-: +Apple II | ✓ | 95%? | ? | full/partial/limited +Atari 2600 | ✓ | 95%? | ? | partial/limited +Atari 7800 | ✓ | 95%? | ? | full/partial/limited +Atari Lynx | ✓ | 95%? | ? | full/partial/limited +ColecoVision | ✓ | 95%? | ? | full/partial/limited +Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | full/partial/limited +GB/GBC | ✓ | 95%? | ? | full/partial/limited +GBA | ✓ | 95%? | ? | full/partial/limited +Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | full/partial/limited +IntelliVision | ✓ | 95%? | ? | full/partial/limited +Master System | ✓ | 95%? | ? | full/partial/limited +N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | full/partial/limited +NGP/NGPC | ✓ | 95%? | N/A | full/partial/limited +NES | ✓ | 95%? | ? | full/partial/limited +PSX | ✓ | 95%? | ? | full/partial/limited +Saturn | ✓ | 95%? | ? | full/partial/limited +SNES | ✓ | 95%? | ? | full/partial/limited +TI-83 | ✓ | 95%? | N/A | full/partial/limited +PC Engine / SG | ✓ | 95%? | ? | full/partial/limited +Virtual Boy | ✓ | 95%? | N/A | full/partial/limited +WonderSwan | ✓ | 95%? | N/A | full/partial/limited +ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | full/partial/limited † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) From 54602ba86fcd016a54148cc11f6b23f08b18422d Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:12:17 +1000 Subject: [PATCH 077/440] Update README.md --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index cd4b382c0c..aca1eaaa64 100644 --- a/README.md +++ b/README.md @@ -29,28 +29,28 @@ The "core" features, common to every system core, are: System | "Core" Features | Game Coverage† | Peripherals | Debugging --:|:-:|:-:|:-:|:-: -Apple II | ✓ | 95%? | ? | full/partial/limited -Atari 2600 | ✓ | 95%? | ? | partial/limited -Atari 7800 | ✓ | 95%? | ? | full/partial/limited -Atari Lynx | ✓ | 95%? | ? | full/partial/limited -ColecoVision | ✓ | 95%? | ? | full/partial/limited -Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | full/partial/limited -GB/GBC | ✓ | 95%? | ? | full/partial/limited -GBA | ✓ | 95%? | ? | full/partial/limited -Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | full/partial/limited -IntelliVision | ✓ | 95%? | ? | full/partial/limited -Master System | ✓ | 95%? | ? | full/partial/limited -N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | full/partial/limited -NGP/NGPC | ✓ | 95%? | N/A | full/partial/limited -NES | ✓ | 95%? | ? | full/partial/limited -PSX | ✓ | 95%? | ? | full/partial/limited -Saturn | ✓ | 95%? | ? | full/partial/limited -SNES | ✓ | 95%? | ? | full/partial/limited -TI-83 | ✓ | 95%? | N/A | full/partial/limited -PC Engine / SG | ✓ | 95%? | ? | full/partial/limited -Virtual Boy | ✓ | 95%? | N/A | full/partial/limited -WonderSwan | ✓ | 95%? | N/A | full/partial/limited -ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | full/partial/limited +Apple II | ✓ | 95%? | ? | ? +Atari 2600 | ✓ | 95%? | ? | partial +Atari 7800 | ✓ | 95%? | ? | partial +Atari Lynx | ✓ | 95%? | ? | limited +ColecoVision | ✓ | 95%? | ? | partial +Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | partial +GB/GBC | ✓ | 95%? | ? | full +GBA | ✓ | 95%? | ? | partial +Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | full +IntelliVision | ✓ | 95%? | ? | partial +Master System | ✓ | 95%? | ? | full +N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | partial +NGP/NGPC | ✓ | 95%? | N/A | limited +NES | ✓ | 95%? | ? | full +PSX | ✓ | 95%? | ? | ? +Saturn | ✓ | 95%? | ? | limited +SNES | ✓ | 95%? | ? | full +TI-83 | ✓ | 95%? | N/A | ? +PC Engine / SG | ✓ | 95%? | ? | full +Virtual Boy | ✓ | 95%? | N/A | ? +WonderSwan | ✓ | 95%? | N/A | partial +ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | full † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) From 5e3e722858575cdfe22e5bb1cf175f5813add5c7 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:20:04 +1000 Subject: [PATCH 078/440] Update README.md --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index aca1eaaa64..648229524b 100644 --- a/README.md +++ b/README.md @@ -30,27 +30,27 @@ The "core" features, common to every system core, are: System | "Core" Features | Game Coverage† | Peripherals | Debugging --:|:-:|:-:|:-:|:-: Apple II | ✓ | 95%? | ? | ? -Atari 2600 | ✓ | 95%? | ? | partial -Atari 7800 | ✓ | 95%? | ? | partial -Atari Lynx | ✓ | 95%? | ? | limited -ColecoVision | ✓ | 95%? | ? | partial -Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | partial -GB/GBC | ✓ | 95%? | ? | full -GBA | ✓ | 95%? | ? | partial -Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | full -IntelliVision | ✓ | 95%? | ? | partial -Master System | ✓ | 95%? | ? | full -N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | partial -NGP/NGPC | ✓ | 95%? | N/A | limited -NES | ✓ | 95%? | ? | full +Atari 2600 | ✓ | 95%? | ? | ◕ +Atari 7800 | ✓ | 95%? | ? | ◕ +Atari Lynx | ✓ | 95%? | ? | ◔ +ColecoVision | ✓ | 95%? | ? | ◕ +Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | ◕ +GB/GBC | ✓ | 95%? | ? | ✓ +GBA | ✓ | 95%? | ? | ◕ +Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | ✓ +IntelliVision | ✓ | 95%? | ? | ◕ +Master System | ✓ | 95%? | ? | ✓ +N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | ◕ +NGP/NGPC | ✓ | 95%? | N/A | ◔ +NES | ✓ | 95%? | ? | ✓ PSX | ✓ | 95%? | ? | ? -Saturn | ✓ | 95%? | ? | limited -SNES | ✓ | 95%? | ? | full +Saturn | ✓ | 95%? | ? | ◔ +SNES | ✓ | 95%? | ? | ✓ TI-83 | ✓ | 95%? | N/A | ? -PC Engine / SG | ✓ | 95%? | ? | full +PC Engine / SG | ✓ | 95%? | ? | ✓ Virtual Boy | ✓ | 95%? | N/A | ? -WonderSwan | ✓ | 95%? | N/A | partial -ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | full +WonderSwan | ✓ | 95%? | N/A | ◕ +ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | ✓ † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) From 200cffabc426e8daccb736b938a239dc9b07e876 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:30:05 +1000 Subject: [PATCH 079/440] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 648229524b..512a878444 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # BizHawk -[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) ![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout) +[![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) +[![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) +[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](#) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). From f1041fc764b7db7eeb575bcb905d4ade58aab3bc Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:30:22 +1000 Subject: [PATCH 080/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 512a878444..1318f4f666 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) -[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](#) +[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)]() A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). From 544b2c07484c13e8e5bf913a09044f5086d23bef Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:30:38 +1000 Subject: [PATCH 081/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1318f4f666..f6f34ba702 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) -[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)]() +[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](javascript:;) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). From e22d10517f3dcedc527a264fd2497f2b16ef3ade Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:31:21 +1000 Subject: [PATCH 082/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6f34ba702..0e45be8132 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) -[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](javascript:;) +[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). From 43286f7ec37ec3120b880f93783e611a991614f9 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:35:54 +1000 Subject: [PATCH 083/440] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0e45be8132..3e7b2a937d 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,11 @@ Jump to: The "core" features, common to every system core, are: * rom format and region detection and a corruption check -* speed control, including frame stepping and rewinding -* input recording (making TAS movies) -* memory view/search/edit in all parts of the emulated HW * 10 savestate slots and save/load to file -* more things I can't remember +* speed control, including frame stepping and rewinding +* memory view/search/edit in all parts of the emulated HW +* input recording (making TAS movies) +* take screenshots and record video System | "Core" Features | Game Coverage† | Peripherals | Debugging --:|:-:|:-:|:-:|:-: From 746606a09d99f30d419563d92ad021d867e2bd7d Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 00:45:58 +1000 Subject: [PATCH 084/440] Update README.md --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3e7b2a937d..88ae2ef065 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Jump to: ## Features -The "core" features, common to every system core, are: +The BizHawk common features (across all cores) are: * rom format and region detection and a corruption check * 10 savestate slots and save/load to file * speed control, including frame stepping and rewinding @@ -29,30 +29,30 @@ The "core" features, common to every system core, are: * input recording (making TAS movies) * take screenshots and record video -System | "Core" Features | Game Coverage† | Peripherals | Debugging +System | BH Common | Accuracy† | Debugging | Peripherals --:|:-:|:-:|:-:|:-: Apple II | ✓ | 95%? | ? | ? -Atari 2600 | ✓ | 95%? | ? | ◕ -Atari 7800 | ✓ | 95%? | ? | ◕ -Atari Lynx | ✓ | 95%? | ? | ◔ -ColecoVision | ✓ | 95%? | ? | ◕ -Commodore 64 | ✓ | 95%? | [some](http://tasvideos.org/Bizhawk/C64.html) | ◕ -GB/GBC | ✓ | 95%? | ? | ✓ -GBA | ✓ | 95%? | ? | ◕ -Genesis | ✓ | 95%? | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) | ✓ -IntelliVision | ✓ | 95%? | ? | ◕ -Master System | ✓ | 95%? | ? | ✓ -N64 | ✓ | 95%? | [all?](http://tasvideos.org/Bizhawk/N64.html) | ◕ -NGP/NGPC | ✓ | 95%? | N/A | ◔ -NES | ✓ | 95%? | ? | ✓ +Atari 2600 | ✓ | 95%? | ◕ | ? +Atari 7800 | ✓ | 95%? | ◕ | ? +Atari Lynx | ✓ | 95%? | ◔ | ? +ColecoVision | ✓ | 95%? | ◕ | ? +Commodore 64 | ✓ | 95%? | ◕ | [some](http://tasvideos.org/Bizhawk/C64.html) +GB/GBC | ✓ | 95%? | ✓ | ? +GBA | ✓ | 95%? | ◕ | ? +Genesis | ✓ | 95%? | ✓ | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) +IntelliVision | ✓ | 95%? | ◕ | ? +Master System | ✓ | 95%? | ✓ | ? +N64 | ✓ | 95%? | ◕ | [all?](http://tasvideos.org/Bizhawk/N64.html) +NGP/NGPC | ✓ | 95%? | ◔ | N/A +NES | ✓ | 95%? | ✓ | ? PSX | ✓ | 95%? | ? | ? -Saturn | ✓ | 95%? | ? | ◔ -SNES | ✓ | 95%? | ? | ✓ -TI-83 | ✓ | 95%? | N/A | ? -PC Engine / SG | ✓ | 95%? | ? | ✓ -Virtual Boy | ✓ | 95%? | N/A | ? -WonderSwan | ✓ | 95%? | N/A | ◕ -ZX Spectrum | ✓ | 95%? | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) | ✓ +Saturn | ✓ | 95%? | ◔ | ? +SNES | ✓ | 95%? | ✓ | ? +TI-83 | ✓ | 95%? | ? | N/A +PC Engine / SG | ✓ | 95%? | ✓ | ? +Virtual Boy | ✓ | 95%? | ? | N/A +WonderSwan | ✓ | 95%? | ◕ | N/A +ZX Spectrum | ✓ | 95%? | ✓ | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) † *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) From c19c7cd5c39087027475a6eff6268c8aea8ce2e5 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 6 Jan 2019 23:05:29 +0300 Subject: [PATCH 085/440] SubNESHawk also Input register shift fix # Conflicts: # BizHawk.Client.EmuHawk/MainForm.Designer.cs # BizHawk.Client.EmuHawk/MainForm.Events.cs # BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs # BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs # BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs --- BizHawk.Client.Common/RomLoader.cs | 9 +- BizHawk.Client.Common/config/Config.cs | 1 + BizHawk.Client.EmuHawk/MainForm.Designer.cs | 10 + BizHawk.Client.EmuHawk/MainForm.Events.cs | 11 + BizHawk.Client.EmuHawk/MainForm.cs | 4 +- .../Base Implementations/NullEmulator.cs | 10 +- .../Interfaces/IEmulator.cs | 2 +- .../BizHawk.Emulation.Cores.csproj | 24 ++ .../Calculator/TI83.IEmulator.cs | 4 +- .../AmstradCPC/AmstradCPC.IEmulator.cs | 4 +- .../Computers/AppleII/AppleII.IEmulator.cs | 4 +- .../Computers/Commodore64/C64.IEmulator.cs | 4 +- .../SinclairSpectrum/ZXSpectrum.IEmulator.cs | 4 +- .../Atari/2600/Atari2600.IEmulator.cs | 4 +- .../Atari/A7800Hawk/A7800Hawk.IEmulator.cs | 4 +- .../Consoles/Atari/lynx/Lynx.cs | 4 +- .../Consoles/Coleco/ColecoVision.IEmulator.cs | 4 +- .../Intellivision/Intellivision.IEmulator.cs | 4 +- .../Consoles/Nintendo/GBA/MGBAHawk.cs | 4 +- .../Consoles/Nintendo/GBA/VBANext.cs | 4 +- .../Nintendo/GBHawk/GBHawk.IEmulator.cs | 4 +- .../GBHawkLink/GBHawkLink.IEmulator.cs | 4 +- .../Nintendo/Gameboy/Gambatte.IEmulator.cs | 4 +- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 4 +- .../Gameboy/GambatteLink.IEmulator.cs | 4 +- .../Consoles/Nintendo/N64/N64.cs | 4 +- .../Consoles/Nintendo/NES/Boards/ExROM.cs | 6 +- .../NES/Boards/UNIF/UNIF_UNL-TF1201.cs | 4 +- .../Consoles/Nintendo/NES/NES.Core.cs | 108 +++++++-- .../Consoles/Nintendo/NES/NES.IStatable.cs | 11 +- .../Consoles/Nintendo/NES/NES.cs | 4 +- .../Consoles/Nintendo/NES/PPU.cs | 11 +- .../Consoles/Nintendo/NES/PPU.regs.cs | 2 +- .../Consoles/Nintendo/NES/PPU.run.cs | 20 +- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 4 +- .../Nintendo/SNES/LibsnesCore.IEmulator.cs | 4 +- .../Consoles/Nintendo/SubNESHawk/ReadMe.txt | 1 + .../SubNESHawk/SubNESHawk.IDebuggable.cs | 74 ++++++ .../SubNESHawk/SubNESHawk.IEmulator.cs | 215 ++++++++++++++++++ .../SubNESHawk/SubNESHawk.IInputPollable.cs | 24 ++ .../SubNESHawk/SubNESHawk.IMemoryDomains.cs | 84 +++++++ .../SubNESHawk/SubNESHawk.ISaveRam.cs | 42 ++++ .../SubNESHawk/SubNESHawk.ISettable.cs | 58 +++++ .../SubNESHawk/SubNESHawk.IStatable.cs | 63 +++++ .../Nintendo/SubNESHawk/SubNESHawk.cs | 80 +++++++ .../SubNESHawk/SubNESHawkControllerDeck.cs | 89 ++++++++ .../SubNESHawk/SubNESHawkControllers.cs | 94 ++++++++ .../Consoles/PC Engine/PCEngine.IEmulator.cs | 4 +- .../Consoles/SNK/DualNeoGeoPort.cs | 4 +- .../Consoles/Sega/SMS/SMS.IEmulator.cs | 4 +- .../Consoles/Sega/gpgx64/GPGX.IEmulator.cs | 74 +++--- .../Consoles/Sony/PSP/PSP.cs | 4 +- .../Consoles/Sony/PSX/Octoshock.cs | 6 +- .../Consoles/WonderSwan/WonderSwan.cs | 4 +- .../Libretro/LibretroCore.cs | 4 +- .../Waterbox/WaterboxCore.cs | 4 +- 56 files changed, 1144 insertions(+), 105 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 3a4b1d69a6..f06cf75020 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -973,7 +973,14 @@ namespace BizHawk.Client.Common if (preference == "neshawk") { - core = CoreInventory.Instance["NES", "NesHawk"]; + if (Global.Config.UseSubNESHawk) + { + core = CoreInventory.Instance["NES", "SubNESHawk"]; + } + else + { + core = CoreInventory.Instance["NES", "NesHawk"]; + } } else { diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index b7f72ab639..60c0071725 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -554,6 +554,7 @@ namespace BizHawk.Client.Common // as this setting spans multiple cores and doesn't actually affect the behavior of any core, // it hasn't been absorbed into the new system public bool GB_AsSGB = false; + public bool UseSubNESHawk = false; public bool NES_InQuickNES = true; public bool SNES_InSnes9x = true; public bool GBA_UsemGBA = true; diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 092908ba95..b7df5e2f76 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -199,6 +199,7 @@ this.GBGambatteMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBGBHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SubNESHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem16 = new System.Windows.Forms.ToolStripSeparator(); this.allowGameDBCoreOverridesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); @@ -1845,6 +1846,7 @@ this.SGBCoreSubmenu, this.GBCoreSubmenu, this.GBInSGBMenuItem, + this.SubNESHawkMenuItem, this.toolStripMenuItem16, this.allowGameDBCoreOverridesToolStripMenuItem, this.toolStripSeparator8, @@ -1982,6 +1984,13 @@ this.GBInSGBMenuItem.Text = "GB in SGB"; this.GBInSGBMenuItem.Click += new System.EventHandler(this.GbInSgbMenuItem_Click); // + // SubNESHawkMenuItem + // + this.SubNESHawkMenuItem.Name = "SubNESHawkMenuItem"; + this.SubNESHawkMenuItem.Size = new System.Drawing.Size(239, 22); + this.SubNESHawkMenuItem.Text = "SubNESHawk"; + this.SubNESHawkMenuItem.Click += new System.EventHandler(this.SubNESHawkMenuItem_Click); + // // toolStripMenuItem16 // this.toolStripMenuItem16.Name = "toolStripMenuItem16"; @@ -4532,6 +4541,7 @@ private System.Windows.Forms.ToolStripMenuItem MovieSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem CoresSubMenu; private System.Windows.Forms.ToolStripMenuItem GBInSGBMenuItem; + private System.Windows.Forms.ToolStripMenuItem SubNESHawkMenuItem; private System.Windows.Forms.ToolStripMenuItem batchRunnerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem DisplayConfigMenuItem; private System.Windows.Forms.ToolStripMenuItem PCEtileViewerToolStripMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index e9bce5e5aa..f524b4bb13 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1215,6 +1215,7 @@ namespace BizHawk.Client.EmuHawk private void CoresSubMenu_DropDownOpened(object sender, EventArgs e) { GBInSGBMenuItem.Checked = Global.Config.GB_AsSGB; + SubNESHawkMenuItem.Checked = Global.Config.UseSubNESHawk; allowGameDBCoreOverridesToolStripMenuItem.Checked = Global.Config.CoreForcingViaGameDB; } @@ -1308,6 +1309,16 @@ namespace BizHawk.Client.EmuHawk } } + private void SubNESHawkMenuItem_Click(object sender, EventArgs e) + { + Global.Config.UseSubNESHawk ^= true; + + if (!Emulator.IsNull()) + { + FlagNeedsReboot(); + } + } + private void AllowGameDBCoreOverridesToolStripMenuItem_Click(object sender, EventArgs e) { Global.Config.CoreForcingViaGameDB ^= true; diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 28f0311d31..a7a40b17aa 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2997,7 +2997,7 @@ namespace BizHawk.Client.EmuHawk } bool render = !_throttle.skipNextFrame || (_currAviWriter?.UsesVideo ?? false); - Emulator.FrameAdvance(Global.ControllerOutput, render, renderSound); + bool new_frame = Emulator.FrameAdvance(Global.ControllerOutput, render, renderSound); Global.MovieSession.HandleMovieAfterFrameLoop(); @@ -3036,7 +3036,7 @@ namespace BizHawk.Client.EmuHawk UpdateToolsAfter(SuppressLua); } - if (!PauseAvi) + if (!PauseAvi && new_frame) { AvFrameAdvance(); } diff --git a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs index 034d1dfbaf..0983f9651c 100644 --- a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs +++ b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs @@ -33,23 +33,23 @@ namespace BizHawk.Emulation.Common public ControllerDefinition ControllerDefinition => NullController.Instance.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (render == false) { - return; + return true; } if (!_settings.SnowyDisplay) { if (_frameBufferClear) { - return; + return true; } _frameBufferClear = true; Array.Clear(_frameBuffer, 0, 256 * 192); - return; + return true; } _frameBufferClear = false; @@ -70,6 +70,8 @@ namespace BizHawk.Emulation.Common } Frame++; + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs index 4d3926d6fc..6920136d94 100644 --- a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs +++ b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs @@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Common /// Whether or not to render video, cores will pass false here in cases such as frame skipping /// Whether or not to render audio, cores will pass here false here in cases such as fast forwarding where bypassing sound may improve speed /// - void FrameAdvance(IController controller, bool render, bool rendersound = true); + bool FrameAdvance(IController controller, bool render, bool rendersound = true); ///

/// Gets the current frame count diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 744a7d8c27..dda627b813 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -1201,6 +1201,30 @@ + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + SubNESHawk.cs + + + diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs index 622664bcc7..ba1f2efde3 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Calculators public ControllerDefinition ControllerDefinition => TI83Controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -59,6 +59,8 @@ namespace BizHawk.Emulation.Cores.Calculators } _isLag = _lagged; + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs index 23a2bfb521..bb7fe9b5f3 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC public ControllerDefinition ControllerDefinition { get; set; } - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC { _lagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs index 8e41c8ba8c..903fc365bd 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs @@ -14,9 +14,11 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public bool DeterministicEmulation => true; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdv(controller, render, rendersound); + + return true; } public void ResetCounters() diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs index 358a02fcff..29aea5b261 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 public ControllerDefinition ControllerDefinition => C64ControllerDefinition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _board.Controller = controller; @@ -47,6 +47,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 DoCycle(); } while (_frameCycles != 0); + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs index 1276521373..56e9f0d376 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ControllerDefinition ControllerDefinition { get; set; } - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { _lagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs index 1dad16b1d3..23585fb39f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -75,6 +75,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } _tia.LineCount = 0; + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs index 11ce9c8f23..667ee16c13 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs @@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public bool slow_access = false; public int slow_countdown; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (_tracer.Enabled) { @@ -88,6 +88,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { _lagcount++; } + + return true; } public void RunCPUCycle() diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs index e234ae4455..24fb8a0095 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs @@ -120,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx public IEmulatorServiceProvider ServiceProvider { get; } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; if (controller.IsPressed("Power")) @@ -135,6 +135,8 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx { LagCount++; } + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs index 6d9dda125f..8d8c7b8b48 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs @@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision public ControllerDefinition ControllerDefinition => ControllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool renderSound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; @@ -163,6 +163,8 @@ namespace BizHawk.Emulation.Cores.ColecoVision { _lagCount++; } + + return true; } public bool use_SGM = false; diff --git a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs index 7f7c1e717d..0d0dd5dee2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Intellivision public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { if (_tracer.Enabled) { @@ -124,6 +124,8 @@ namespace BizHawk.Emulation.Cores.Intellivision { SoftReset(); } + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs index 0028c7b4e9..264d658e98 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.cs @@ -67,7 +67,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public ControllerDefinition ControllerDefinition => GBA.GBAController; - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; if (controller.IsPressed("Power")) @@ -97,6 +97,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA // this should be called in hblank on the appropriate line, but until we implement that, just do it here _scanlinecb?.Invoke(); + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index 676210608f..247d7fd68d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -95,7 +95,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA public IEmulatorServiceProvider ServiceProvider { get; private set; } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; @@ -108,6 +108,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA if (IsLagFrame) LagCount++; + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index e0aa0baeef..ca42c1472e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public bool in_vblank; public bool vblank_rise; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); @@ -74,6 +74,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { _lagcount++; } + + return true; } public void do_frame() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 1cebe9f5b4..dc431a50fc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); //Update the color palette if a setting changed @@ -86,6 +86,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { _lagcount++; } + + return true; } public void do_frame() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs index 2b55424647..c0b371b389 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public ControllerDefinition ControllerDefinition => GbController; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdvancePrep(controller); if (_syncSettings.EqualLengthFrames) @@ -68,6 +68,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } FrameAdvancePost(); + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index 1f1891e1a5..b0bdd405d9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy LibGambatte.gambatte_setlayers(GambatteState, (_settings.DisplayBG ? 1 : 0) | (_settings.DisplayOBJ ? 2 : 0) | (_settings.DisplayWindow ? 4 : 0)); } - internal void FrameAdvancePost() + internal bool FrameAdvancePost() { if (IsLagFrame) { @@ -352,6 +352,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } endofframecallback?.Invoke(LibGambatte.gambatte_cpuread(GambatteState, 0xff40)); + + return true; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs index 3a835ee5a2..c10f340eae 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public ControllerDefinition ControllerDefinition => DualGbController; - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { LCont.Clear(); RCont.Clear(); @@ -148,6 +148,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { LagCount++; } + + return true; } public int Frame { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs index b4c68bf03f..342eaef8c4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs @@ -221,7 +221,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 RunThreadAction(() => { _pendingThreadTerminate = true; }); } - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _inputProvider.Controller = controller; @@ -258,6 +258,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 if(!api.IsCrashed) Frame++; + + return true; } public string SystemId { get { return "N64"; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs index 61a0c5fe7c..ce0e72510f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs @@ -244,7 +244,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int bank_1k = addr >> 10; int ofs = addr & ((1 << 10) - 1); - if (exram_mode == 1 && NES.ppu.ppuphase == PPU.PPUPHASE.BG) + if (exram_mode == 1 && NES.ppu.ppuphase == PPU.PPU_PHASE_BG) { int exram_addr = last_nt_read; int bank_4k = EXRAM[exram_addr] & 0x3F; @@ -261,9 +261,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (NES.ppu.reg_2000.obj_size_16) { bool isPattern = NES.ppu.PPUON; - if (NES.ppu.ppuphase == PPU.PPUPHASE.OBJ && isPattern) + if (NES.ppu.ppuphase == PPU.PPU_PHASE_OBJ && isPattern) bank_1k = a_banks_1k[bank_1k]; - else if (NES.ppu.ppuphase == PPU.PPUPHASE.BG && isPattern) + else if (NES.ppu.ppuphase == PPU.PPU_PHASE_BG && isPattern) bank_1k = b_banks_1k[bank_1k]; else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs index 04df29aadc..c8df6cac0d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/UNIF/UNIF_UNL-TF1201.cs @@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0xF003: IRQa = value.Bit(1); IRQSignal = false; - if (NES.ppu.ppuphase !=PPU.PPUPHASE.VBL) + if (NES.ppu.ppuphase !=PPU.PPU_PHASE_VBL) IRQCount -= 8; break; } @@ -88,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public override void ClockPPU() { - if ((NES.ppu.ppuphase != PPU.PPUPHASE.VBL))// && IRQa) + if ((NES.ppu.ppuphase != PPU.PPU_PHASE_VBL))// && IRQa) { IRQpre--; if (IRQpre==0) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 5d5a01ed83..851291e2a1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -79,7 +79,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES magicSoundProvider = null; } - class MagicSoundProvider : ISoundProvider, IDisposable + public class MagicSoundProvider : ISoundProvider, IDisposable { BlipBuffer blip; NES nes; @@ -157,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } } - MagicSoundProvider magicSoundProvider; + public MagicSoundProvider magicSoundProvider; public void HardReset() { @@ -311,7 +311,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES bool resetSignal; bool hardResetSignal; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -377,12 +377,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else { - ppu.ppu_init_frame(); - - ppu.do_vbl = true; - ppu.do_active_sl = true; - ppu.do_pre_vbl = true; - // do the vbl ticks seperate, that will save us a few checks that don't happen in active region while (ppu.do_vbl) { @@ -415,6 +409,50 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // turn off all cheats // any cheats still active will be re-applied by the buspoke at the start of the next frame num_cheats = 0; + + return true; + } + + // these variables are for subframe input control + public bool controller_was_latched; + public bool frame_is_done; + public bool current_strobe; + public bool new_strobe; + public bool alt_lag; + public byte ctrl_1 = 0; + public byte ctrl_2 = 0; + public byte ctrl_1_new = 0; + public byte ctrl_2_new = 0; + public int shift_1; + public int shift_2; + public bool use_sub_input = false; + // this function will run one step of the ppu + // it will return whether the controller is read or not. + public void do_single_step(out bool cont_read, out bool frame_done) + { + controller_was_latched = false; + frame_is_done = false; + + current_strobe = new_strobe; + if (ppu.ppudead > 0) + { + ppu.NewDeadPPU(); + } + else if (ppu.do_vbl) + { + ppu.TickPPU_VBL(); + } + else if (ppu.do_active_sl) + { + ppu.TickPPU_active(); + } + else if (ppu.do_pre_vbl) + { + ppu.TickPPU_preVBL(); + } + + cont_read = controller_was_latched; + frame_done = frame_is_done; } //PAL: @@ -736,6 +774,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES var si = new StrobeInfo(latched4016, value); ControllerDeck.Strobe(si, _controller); latched4016 = value; + new_strobe = (value & 1) > 0; + if (current_strobe && !new_strobe) + { + controller_was_latched = true; + alt_lag = false; + + if (use_sub_input) + { + shift_1 = 7; + shift_2 = 7; + + ctrl_1 = ctrl_1_new; + ctrl_2 = ctrl_2_new; + } + } + + if (use_sub_input && new_strobe) + { + shift_1 = 7; + shift_2 = 7; + } } byte read_joyport(int addr) @@ -743,14 +802,35 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES InputCallbacks.Call(); lagged = false; byte ret = 0; - if (_isVS) + + if (use_sub_input) { - // for whatever reason, in VS left and right controller have swapped regs - ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); + if (addr == 0x4016) + { + if (shift_1 >= 0) { ret = (byte)((ctrl_1 >> shift_1) & 1); } + else { ret = 1; } + + if (!current_strobe) { shift_1 -= 1; } + } + else + { + if (shift_2 >= 0) { ret = (byte)((ctrl_2 >> shift_2) & 1); } + else { ret = 1; } + + if (!current_strobe) { shift_2 -= 1; } + } } else { - ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); + if (_isVS) + { + // for whatever reason, in VS left and right controller have swapped regs + ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); + } + else + { + ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); + } } ret &= 0x1f; @@ -810,7 +890,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte DummyReadMemory(ushort addr) { return 0; } - private void ApplySystemBusPoke(int addr, byte value) + public void ApplySystemBusPoke(int addr, byte value) { if (addr < 0x2000) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs index e2dd212602..7c7b3f7f17 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs @@ -82,7 +82,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("VS_Coin", ref VS_coin_inserted); ser.Sync("VS_ROM_Control", ref VS_ROM_control); - ser.BeginSection("Board"); + // single cycle execution related + ser.Sync("current_strobe", ref current_strobe); + ser.Sync("new_strobe", ref new_strobe); + ser.Sync("ctrl_1", ref ctrl_1); + ser.Sync("ctrl_2", ref ctrl_2); + ser.Sync("shift_1", ref shift_1); + ser.Sync("shift_2", ref shift_2); + ser.Sync("use_sub_input", ref use_sub_input); + + ser.BeginSection("Board"); Board.SyncState(ser); if (Board is NESBoardBase && !((NESBoardBase)Board).SyncStateFlag) throw new InvalidOperationException("the current NES mapper didnt call base.SyncState"); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 5da37f44c4..62d534f935 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -126,7 +126,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public DisplayType Region { get { return _display_type; } } - class MyVideoProvider : IVideoProvider + public class MyVideoProvider : IVideoProvider { //public int ntsc_top = 8; //public int ntsc_bottom = 231; @@ -246,7 +246,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int VsyncDenominator => emu.VsyncDen; } - MyVideoProvider videoProvider; + public MyVideoProvider videoProvider; [Obsolete] // with the changes to both nes and quicknes cores, nothing uses this anymore public static readonly ControllerDefinition NESController = diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 36df0ab4c3..b04744f5f8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -158,11 +158,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES return nes.Board.PeekPPU(addr); } - public enum PPUPHASE - { - VBL, BG, OBJ - }; - public PPUPHASE ppuphase; + public static int PPU_PHASE_VBL = 0; + public static int PPU_PHASE_BG = 1; + public static int PPU_PHASE_OBJ = 2; + + public int ppuphase; private readonly NES nes; public PPU(NES nes) @@ -247,6 +247,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("OAM", ref OAM, false); ser.Sync("soam", ref soam, false); ser.Sync("PALRAM", ref PALRAM, false); + ser.Sync("ppuphase", ref ppuphase); ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow); ser.Sync("Reg2002_objhit", ref Reg2002_objhit); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 0fa0bc98cd..739338840a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -551,7 +551,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //does this take 4x longer? nestopia indicates so perhaps... int addr = ppur.get_2007access(); - if (ppuphase == PPUPHASE.BG) + if (ppuphase == PPU_PHASE_BG) { if (show_bg_new) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index 3b2199bf06..ead5ce61b5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -151,7 +151,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // These things happen at the start of every frame //Reg2002_vblank_active = true; //Reg2002_vblank_active_pending = true; - ppuphase = PPUPHASE.VBL; + ppuphase = PPU_PHASE_VBL; bgdata = new BGDataRecord[34]; } @@ -194,6 +194,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { do_vbl = false; ppur.status.sl = 0; + do_active_sl = true; } } } @@ -216,7 +217,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES sprite_zero_in_range = false; yp = ppur.status.sl - 1; - ppuphase = PPUPHASE.BG; + ppuphase = PPU_PHASE_BG; // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM are written to from // the current location of PPUADDR" @@ -615,7 +616,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) soam_index_prev = 8; - ppuphase = PPUPHASE.OBJ; + ppuphase = PPU_PHASE_OBJ; spriteHeight = reg_2000.obj_size_16 ? 16 : 8; @@ -926,7 +927,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { if (ppur.status.cycle == 320) { - ppuphase = PPUPHASE.BG; + ppuphase = PPU_PHASE_BG; xt = 0; xp = 0; } @@ -992,6 +993,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.sl == 241) { do_active_sl = false; + do_pre_vbl = true; } } } @@ -1012,6 +1014,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.sl == 241 + preNMIlines) { do_pre_vbl = false; + do_vbl = true; + + ppu_init_frame(); + nes.frame_is_done = true; } } } @@ -1033,6 +1039,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.cycle == 241 * 341 - start_up_offset) { ppudead--; + + ppu_init_frame(); + + do_vbl = true; + + nes.frame_is_done = true; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 899ae0254f..aad8579a37 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -179,7 +179,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES #endregion - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { CheckDisposed(); using (FP.Save()) @@ -211,6 +211,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES if (CB1 != null) CB1(); if (CB2 != null) CB2(); } + + return true; } IntPtr Context; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs index a245fbdbbf..e16511cbaa 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IEmulator.cs @@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; @@ -80,6 +80,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES { LagCount++; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt new file mode 100644 index 0000000000..bc60bf4b01 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/ReadMe.txt @@ -0,0 +1 @@ +TODO: diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs new file mode 100644 index 0000000000..fe41918f23 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IDebuggable.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + return new Dictionary + { + /* + ["A"] = cpu.A, + ["X"] = cpu.X, + ["Y"] = cpu.Y, + ["S"] = cpu.S, + ["PC"] = cpu.PC, + ["Flag C"] = cpu.FlagC, + ["Flag Z"] = cpu.FlagZ, + ["Flag I"] = cpu.FlagI, + ["Flag D"] = cpu.FlagD, + ["Flag B"] = cpu.FlagB, + ["Flag V"] = cpu.FlagV, + ["Flag N"] = cpu.FlagN, + ["Flag T"] = cpu.FlagT + */ + }; + } + + public void SetCpuRegister(string register, int value) + { + switch (register) + { + default: + throw new InvalidOperationException(); + case "A": + //cpu.A = (byte)value; + break; + case "X": + //cpu.X = (byte)value; + break; + case "Y": + //cpu.Y = (byte)value; + break; + case "S": + //cpu.S = (byte)value; + break; + case "PC": + //cpu.PC = (ushort)value; + break; + case "Flag I": + //cpu.FlagI = value > 0; + break; + } + } + + public bool CanStep(StepType type) + { + return false; + } + + public IMemoryCallbackSystem MemoryCallbacks { get; private set; } + + [FeatureNotImplemented] + public void Step(StepType type) { throw new NotImplementedException(); } + + public long TotalExecutedCycles + { + get { return subnes.cpu.TotalExecutedCycles; } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs new file mode 100644 index 0000000000..3fef3f0d45 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -0,0 +1,215 @@ +using System; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IEmulator + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + + public bool FrameAdvance(IController controller, bool render, bool rendersound) + { + //Console.WriteLine("-----------------------FRAME-----------------------"); + if (_tracer.Enabled) + { + subnes.cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + subnes.cpu.TraceCallback = null; + } + + _frame++; + + if (controller.IsPressed("Power")) + { + HardReset(); + } + + if (controller.IsPressed("Reset")) + { + SoftReset(); + } + + _islag = true; + subnes.alt_lag = true; + + GetControllerState(controller); + + do_frame(); + + bool ret = pass_a_frame; + + if (pass_a_frame) + { + subnes.videoProvider.FillFrameBuffer(); + } + + _islag = subnes.alt_lag; + + if (_islag) + { + _lagcount++; + } + + return ret; + } + + public bool stop_cur_frame; + public bool pass_new_input; + public bool pass_a_frame; + public byte ctrl_byte_1; + public byte ctrl_byte_2; + + public void do_frame() + { + stop_cur_frame = false; + while (!stop_cur_frame) + { + subnes.do_single_step(out pass_new_input, out pass_a_frame); + stop_cur_frame |= pass_a_frame; + stop_cur_frame |= pass_new_input; + } + } + + public void GetControllerState(IController controller) + { + InputCallbacks.Call(); + + ctrl_byte_1 = _controllerDeck.ReadPort1(controller); + ctrl_byte_2 = _controllerDeck.ReadPort2(controller); + + subnes.ctrl_1_new = ctrl_byte_1; + subnes.ctrl_2_new = ctrl_byte_2; + } + + public int Frame => _frame; + + public string SystemId => "NES"; + + public bool DeterministicEmulation { get; set; } + + public void ResetCounters() + { + _frame = 0; + _lagcount = 0; + _islag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + subnes.Dispose(); + } + /* + #region Video provider + + public int _frameHz = 60; + + public int[] _vidbuffer = new int[160 * 2 * 144]; + public int[] buff_L = new int[160 * 144]; + public int[] buff_R = new int[160 * 144]; + + public int[] GetVideoBuffer() + { + // combine the 2 video buffers from the instances + for (int i = 0; i < 144; i++) + { + for (int j = 0; j < 160; j++) + { + _vidbuffer[i * 320 + j] = buff_L[i * 160 + j]; + _vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j]; + } + } + + return _vidbuffer; + } + + public int VirtualWidth => 160 * 2; + public int VirtualHeight => 144; + public int BufferWidth => 160 * 2; + public int BufferHeight => 144; + public int BackgroundColor => unchecked((int)0xFF000000); + public int VsyncNumerator => _frameHz; + public int VsyncDenominator => 1; + + public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; + public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; + + public uint[] color_palette = new uint[4]; + + #endregion + + #region audio + + public bool CanProvideAsync => false; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } + } + + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + short[] temp_samp_L; + short[] temp_samp_R; + + int nsamp_L; + int nsamp_R; + + L.audio.GetSamplesSync(out temp_samp_L, out nsamp_L); + R.audio.GetSamplesSync(out temp_samp_R, out nsamp_R); + + if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Left) + { + samples = temp_samp_L; + nsamp = nsamp_L; + } + else if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Right) + { + samples = temp_samp_R; + nsamp = nsamp_R; + } + else + { + samples = new short[0]; + nsamp = 0; + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + L.audio.DiscardSamples(); + R.audio.DiscardSamples(); + } + + private void GetSamples(short[] samples) + { + + } + + public void DisposeSound() + { + L.audio.DisposeSound(); + R.audio.DisposeSound(); + } + + #endregion + */ + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs new file mode 100644 index 0000000000..04c6faea5c --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IInputPollable + { + public int LagCount + { + get { return _lagcount; } + set { _lagcount = value; } + } + + public bool IsLagFrame + { + get { return _islag; } + set { _islag = value; } + } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + + public bool _islag = true; + private int _lagcount; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs new file mode 100644 index 0000000000..b1aafedaf7 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IMemoryDomains.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk + { + private MemoryDomainList _memoryDomains; + private bool _memoryDomainsSetup = false; + + private void SetupMemoryDomains() + { + var domains = new List(); + var RAM = new MemoryDomainByteArray("RAM", MemoryDomain.Endian.Little, subnes.ram, true, 1); + var SystemBus = new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Little, + addr => subnes.PeekMemory((ushort)addr), (addr, value) => subnes.ApplySystemBusPoke((int)addr, value), 1); + var PPUBus = new MemoryDomainDelegate("PPU Bus", 0x4000, MemoryDomain.Endian.Little, + addr => subnes.ppu.ppubus_peek((int)addr), (addr, value) => subnes.ppu.ppubus_write((int)addr, value), 1); + var CIRAMdomain = new MemoryDomainByteArray("CIRAM (nametables)", MemoryDomain.Endian.Little, subnes.CIRAM, true, 1); + var OAMdoman = new MemoryDomainByteArray("OAM", MemoryDomain.Endian.Unknown, subnes.ppu.OAM, true, 1); + + domains.Add(RAM); + domains.Add(SystemBus); + domains.Add(PPUBus); + domains.Add(CIRAMdomain); + domains.Add(OAMdoman); + + if (!(subnes.Board is NES.FDS) && subnes.Board.SaveRam != null) + { + var BatteryRam = new MemoryDomainByteArray("Battery RAM", MemoryDomain.Endian.Little, subnes.Board.SaveRam, true, 1); + domains.Add(BatteryRam); + } + + if (subnes.Board.ROM != null) + { + var PRGROM = new MemoryDomainByteArray("PRG ROM", MemoryDomain.Endian.Little, subnes.Board.ROM, true, 1); + domains.Add(PRGROM); + } + + if (subnes.Board.VROM != null) + { + var CHRROM = new MemoryDomainByteArray("CHR VROM", MemoryDomain.Endian.Little, subnes.Board.VROM, true, 1); + domains.Add(CHRROM); + } + + if (subnes.Board.VRAM != null) + { + var VRAM = new MemoryDomainByteArray("VRAM", MemoryDomain.Endian.Little, subnes.Board.VRAM, true, 1); + domains.Add(VRAM); + } + + if (subnes.Board.WRAM != null) + { + var WRAM = new MemoryDomainByteArray("WRAM", MemoryDomain.Endian.Little, subnes.Board.WRAM, true, 1); + domains.Add(WRAM); + } + + // if there were more boards with special ram sets, we'd want to do something more general + if (subnes.Board is NES.FDS) + { + domains.Add((subnes.Board as NES.FDS).GetDiskPeeker()); + } + else if (subnes.Board is NES.ExROM) + { + domains.Add((subnes.Board as NES.ExROM).GetExRAM()); + } + + if (!_memoryDomainsSetup) + { + _memoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(_memoryDomains); + _memoryDomainsSetup = true; + } + else + { + var src = new MemoryDomainList(domains); + _memoryDomains.MergeList(src); + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs new file mode 100644 index 0000000000..1d61877e5b --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISaveRam.cs @@ -0,0 +1,42 @@ +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : ISaveRam + { + public bool SaveRamModified + { + get + { + if (subnes.Board == null) return false; + if (subnes.Board is NES.FDS) return true; + if (subnes.Board.SaveRam == null) return false; + return true; + } + } + + public byte[] CloneSaveRam() + { + if (subnes.Board is NES.FDS) + return (subnes.Board as NES.FDS).ReadSaveRam(); + + if (subnes.Board == null || subnes.Board.SaveRam == null) + return null; + return (byte[])subnes.Board.SaveRam.Clone(); + } + + public void StoreSaveRam(byte[] data) + { + if (subnes.Board is NES.FDS) + { + (subnes.Board as NES.FDS).StoreSaveRam(data); + return; + } + + if (subnes.Board == null || subnes.Board.SaveRam == null) + return; + Array.Copy(data, subnes.Board.SaveRam, data.Length); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs new file mode 100644 index 0000000000..9db3f0acc1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs @@ -0,0 +1,58 @@ +using System; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IEmulator, IStatable, ISettable + { + public SubNESHawkSettings GetSettings() + { + return subnesSettings.Clone(); + } + + public SubNESHawkSyncSettings GetSyncSettings() + { + return subnesSyncSettings.Clone(); + } + + public bool PutSettings(SubNESHawkSettings o) + { + subnesSettings = o; + return false; + } + + public bool PutSyncSettings(SubNESHawkSyncSettings o) + { + bool ret = SubNESHawkSyncSettings.NeedsReboot(subnesSyncSettings, o); + subnesSyncSettings = o; + return ret; + } + + private SubNESHawkSettings subnesSettings = new SubNESHawkSettings(); + public SubNESHawkSyncSettings subnesSyncSettings = new SubNESHawkSyncSettings(); + + public class SubNESHawkSettings + { + public SubNESHawkSettings Clone() + { + return (SubNESHawkSettings)MemberwiseClone(); + } + } + + public class SubNESHawkSyncSettings + { + public SubNESHawkSyncSettings Clone() + { + return (SubNESHawkSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(SubNESHawkSyncSettings x, SubNESHawkSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs new file mode 100644 index 0000000000..d6a092971e --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs @@ -0,0 +1,63 @@ +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public partial class SubNESHawk : IStatable + { + public bool BinarySaveStatesPreferred => true; + + public void SaveStateText(TextWriter writer) + { + subnes.SaveStateText(writer); + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + subnes.LoadStateText(reader); + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + subnes.SaveStateBinary(bw); + // other variables + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + subnes.LoadStateBinary(br); + // other variables + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + //private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; + + private void SyncState(Serializer ser) + { + ser.Sync("Lag", ref _lagcount); + ser.Sync("Frame", ref _frame); + ser.Sync("IsLag", ref _islag); + ser.Sync("pass_a_frame", ref pass_a_frame); + ser.Sync("pass_new_input", ref pass_new_input); + ser.Sync("ctrl_byte_1", ref ctrl_byte_1); + ser.Sync("ctrl_byte_2", ref ctrl_byte_2); + + _controllerDeck.SyncState(ser); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs new file mode 100644 index 0000000000..a04a68f7f8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -0,0 +1,80 @@ +using System; + +using BizHawk.Emulation.Common; + +using BizHawk.Emulation.Cores.Nintendo.NES; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + [Core( + "SubNESHawk", + "", + isPorted: false, + isReleased: false)] + [ServiceNotApplicable(typeof(IDriveLight))] + public partial class SubNESHawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, + ISettable + { + public NES.NES subnes; + + [CoreConstructor("NES")] + public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings) + { + var ser = new BasicServiceProvider(this); + + subnesSettings = (SubNESHawkSettings)settings ?? new SubNESHawkSettings(); + subnesSyncSettings = (SubNESHawkSyncSettings)syncSettings ?? new SubNESHawkSyncSettings(); + _controllerDeck = new SubNESHawkControllerDeck(SubNESHawkControllerDeck.DefaultControllerName, SubNESHawkControllerDeck.DefaultControllerName); + + CoreComm = comm; + + var temp_set = new NES.NES.NESSettings(); + + var temp_sync = new NES.NES.NESSyncSettings(); + + subnes = new NES.NES(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game, rom, temp_set, temp_sync); + + ser.Register(subnes.videoProvider); + ser.Register(subnes.magicSoundProvider); + + _tracer = new TraceBuffer { Header = subnes.cpu.TraceHeader }; + ser.Register(_tracer); + + ServiceProvider = ser; + + SetupMemoryDomains(); + + HardReset(); + + // input override for subframe input + subnes.use_sub_input = true; + } + + public void HardReset() + { + subnes.HardReset(); + } + + public void SoftReset() + { + subnes.Board.NESSoftReset(); + subnes.cpu.NESSoftReset(); + subnes.apu.NESSoftReset(); + subnes.ppu.NESSoftReset(); + } + + public DisplayType Region => DisplayType.NTSC; + + public int _frame = 0; + + private readonly SubNESHawkControllerDeck _controllerDeck; + + private readonly ITraceable _tracer; + + private void ExecFetch(ushort addr) + { + MemoryCallbacks.CallExecutes(addr, "System Bus"); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs new file mode 100644 index 0000000000..7f2ecfae40 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + public class SubNESHawkControllerDeck + { + public SubNESHawkControllerDeck(string controller1Name, string controller2Name) + { + if (!ValidControllerTypes.ContainsKey(controller1Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller1Name); + } + + if (!ValidControllerTypes.ContainsKey(controller2Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller2Name); + } + + Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); + Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2); + + Definition = new ControllerDefinition + { + Name = Port1.Definition.Name, + BoolButtons = Port1.Definition.BoolButtons + .Concat(Port2.Definition.BoolButtons) + .Concat(new[] + { + "Power", + "Reset", + }) + .ToList() + }; + } + + public byte ReadPort1(IController c) + { + return Port1.Read(c); + } + + public byte ReadPort2(IController c) + { + return Port2.Read(c); + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + ser.BeginSection("Port1"); + Port1.SyncState(ser); + ser.EndSection(); + + ser.BeginSection("Port2"); + Port2.SyncState(ser); + ser.EndSection(); + } + + private readonly IPort Port1; + private readonly IPort Port2; + + private static Dictionary _controllerTypes; + + public static Dictionary ValidControllerTypes + { + get + { + if (_controllerTypes == null) + { + _controllerTypes = typeof(SubNESHawkControllerDeck).Assembly + .GetTypes() + .Where(t => typeof(IPort).IsAssignableFrom(t)) + .Where(t => !t.IsAbstract && !t.IsInterface) + .ToDictionary(tkey => tkey.DisplayName()); + } + + return _controllerTypes; + } + } + + public static string DefaultControllerName => typeof(StandardControls).DisplayName(); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs new file mode 100644 index 0000000000..44e9e5e98d --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs @@ -0,0 +1,94 @@ +using System; + +using System.ComponentModel; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk +{ + /// + /// Represents a Standard Nintendo Controller + /// + public interface IPort + { + byte Read(IController c); + + ControllerDefinition Definition { get; } + + void SyncState(Serializer ser); + + int PortNum { get; } + } + + [DisplayName("NES Controller")] + public class StandardControls : IPort + { + public StandardControls(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition + { + Name = "NES Controller", + BoolButtons = BaseDefinition + .Select(b => "P" + PortNum + " " + b) + .ToList() + }; + } + + public int PortNum { get; } + + public ControllerDefinition Definition { get; } + + public byte Read(IController c) + { + byte result = 0; + + if (c.IsPressed(Definition.BoolButtons[0])) + { + result |= 8; + } + if (c.IsPressed(Definition.BoolButtons[1])) + { + result |= 4; + } + if (c.IsPressed(Definition.BoolButtons[2])) + { + result |= 2; + } + if (c.IsPressed(Definition.BoolButtons[3])) + { + result |= 1; + } + if (c.IsPressed(Definition.BoolButtons[4])) + { + result |= 16; + } + if (c.IsPressed(Definition.BoolButtons[5])) + { + result |= 32; + } + if (c.IsPressed(Definition.BoolButtons[6])) + { + result |= 64; + } + if (c.IsPressed(Definition.BoolButtons[7])) + { + result |= 128; + } + + return result; + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A" + }; + + public void SyncState(Serializer ser) + { + //nothing + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs index 5fa7f01d7e..6b46010327 100644 --- a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.IEmulator.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.PCEngine public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -39,6 +39,8 @@ namespace BizHawk.Emulation.Cores.PCEngine { _isLag = false; } + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs index 462b62fbee..ae20720922 100644 --- a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs @@ -47,7 +47,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK _serviceProvider.Register(_videoProvider); } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { var t1 = Task.Run(() => { @@ -67,6 +67,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK Frame++; _soundProvider.Fetch(); _videoProvider.Fetch(); + + return true; } #region link cable diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index 1ac7e86924..d3fbefd440 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } } - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; _lagged = true; @@ -86,6 +86,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { _isLag = false; } + + return true; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs index e0a3ac20b1..475d1562fc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IEmulator.cs @@ -7,45 +7,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { public IEmulatorServiceProvider ServiceProvider { get; private set; } - public ControllerDefinition ControllerDefinition { get; private set; } - - // TODO: use render and rendersound - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public ControllerDefinition ControllerDefinition { get; private set; } + + // TODO: use render and rendersound + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { if (controller.IsPressed("Reset")) Core.gpgx_reset(false); if (controller.IsPressed("Power")) - Core.gpgx_reset(true); - if (_cds != null) - { - var prev = controller.IsPressed("Previous Disk"); - var next = controller.IsPressed("Next Disk"); - int newDisk = _discIndex; - if (prev && !_prevDiskPressed) - newDisk--; - if (next && !_nextDiskPressed) - newDisk++; - - _prevDiskPressed = prev; - _nextDiskPressed = next; - - if (newDisk < -1) - newDisk = -1; - if (newDisk >= _cds.Length) - newDisk = _cds.Length - 1; - - if (newDisk != _discIndex) - { - _discIndex = newDisk; - Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex])); - Console.WriteLine("IMMA CHANGING MAH DISKS"); - } - } - - // this shouldn't be needed, as nothing has changed - // if (!Core.gpgx_get_control(input, inputsize)) - // throw new Exception("gpgx_get_control() failed!"); - + Core.gpgx_reset(true); + if (_cds != null) + { + var prev = controller.IsPressed("Previous Disk"); + var next = controller.IsPressed("Next Disk"); + int newDisk = _discIndex; + if (prev && !_prevDiskPressed) + newDisk--; + if (next && !_nextDiskPressed) + newDisk++; + + _prevDiskPressed = prev; + _nextDiskPressed = next; + + if (newDisk < -1) + newDisk = -1; + if (newDisk >= _cds.Length) + newDisk = _cds.Length - 1; + + if (newDisk != _discIndex) + { + _discIndex = newDisk; + Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex])); + Console.WriteLine("IMMA CHANGING MAH DISKS"); + } + } + + // this shouldn't be needed, as nothing has changed + // if (!Core.gpgx_get_control(input, inputsize)) + // throw new Exception("gpgx_get_control() failed!"); + ControlConverter.ScreenWidth = vwidth; ControlConverter.ScreenHeight = vheight; ControlConverter.Convert(controller, input); @@ -66,6 +66,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx if (_cds != null) DriveLightOn = _drivelight; + + return true; } public int Frame { get; private set; } @@ -96,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx if (_elf != null) _elf.Dispose(); if (_cds != null) - foreach (var cd in _cds) + foreach (var cd in _cds) cd.Dispose(); _disposed = true; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs index 5c43900826..55157f7abe 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs @@ -131,7 +131,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSP } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; UpdateInput(controller); @@ -147,6 +147,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSP //nsampavail = PPSSPPDll.mixsound(audiobuffer, audiobuffer.Length / 2); LogFlush(); //Console.WriteLine("Audio Service: {0}", nsampavail); + + return true; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index 807558d6b3..eca318a577 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -743,7 +743,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX private IController _controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; FrameAdvance_PrepDiscState(); @@ -801,7 +801,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX LagCount++; //what happens to sound in this case? - if (render == false) return; + if (render == false) return true; OctoshockDll.ShockFramebufferInfo fb = new OctoshockDll.ShockFramebufferInfo(); @@ -843,6 +843,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSX if (sbuffcontains * 2 > sbuff.Length) throw new InvalidOperationException("shock_GetSamples returned too many samples: " + sbuffcontains); OctoshockDll.shock_GetSamples(psx, samples); } + + return true; } public ControllerDefinition ControllerDefinition { get; private set; } diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 49f91a1824..b5224065ea 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan } } - public void FrameAdvance(IController controller, bool render, bool rendersound = true) + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; IsLagFrame = true; @@ -79,6 +79,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan if (IsLagFrame) LagCount++; + + return true; } public CoreComm CoreComm { get; private set; } diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs index f52709963b..3d3fca7bb9 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs @@ -154,11 +154,13 @@ namespace BizHawk.Emulation.Cores.Libretro private IController _controller; - public void FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool rendersound) { _controller = controller; api.CMD_Run(); timeFrameCounter++; + + return true; } GCHandle vidBufferHandle; diff --git a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs index 3c717bb65f..f202a6b3dd 100644 --- a/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs +++ b/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs @@ -191,7 +191,7 @@ namespace BizHawk.Emulation.Cores.Waterbox protected virtual void FrameAdvancePost() { } - public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true) + public unsafe bool FrameAdvance(IController controller, bool render, bool rendersound = true) { using (_exe.EnterExit()) { @@ -218,6 +218,8 @@ namespace BizHawk.Emulation.Cores.Waterbox FrameAdvancePost(); } } + + return true; } private bool _disposed = false; From c21422c396de399ccbbd18040f5ca485e5b7d50f Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 01:29:37 +1000 Subject: [PATCH 086/440] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 88ae2ef065..280247c4af 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -tl;dr: click the "latest" button above to grab it. The changelog is [here on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix versions**, copy `config.ini` to keep settings. +tl;dr: click the "latest" button above to grab it. The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix versions**, copy `config.ini` to keep settings. Jump to: * [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) @@ -66,7 +66,7 @@ Released binaries can be found right here on GitHub: [![Windows | binaries](https://img.shields.io/badge/Windows-binaries-%230078D6.svg?logo=windows&logoColor=0078D6&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) -Click `BizHawk-.zip` to download it. Also note the changelog, the full version of which is [on tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix different versions** of BizHawk, keep each version in its own folder. +Click `BizHawk-.zip` to download it. Also note the changelog, the full version of which is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix different versions** of BizHawk, keep each version in its own folder. Before you start (by running `EmuHawk.exe`), you'll need the following Windows-only prerequisites installed. You can get them all at once with [this program](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). * .NET Framework 4.6.1 @@ -82,7 +82,7 @@ Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported f ## Installing — GNU+Linux and macOS -Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see tasvideos.org](http://tasvideos.org/Bizhawk/ReleaseHistory.html). +Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see TASVideos here](http://tasvideos.org/Bizhawk/ReleaseHistory.html). [![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) [![Debian (Launchpad) | bizhawk](https://img.shields.io/badge/Debian_(Launchpad)-bizhawk-%23A81D33.svg?logo=debian&style=popout)](https://example.com/bizhawk) @@ -140,6 +140,8 @@ TODO ## Usage (TASing) +This section refers to BizHawk specifically. For resources on TASing in general, see [Welcome to TASVideos](http://tasvideos.org/WelcomeToTASVideos.html). + TODO [Commandline](http://tasvideos.org/Bizhawk/CommandLine.html) @@ -152,7 +154,7 @@ TODO ## Support and troubleshooting -A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at tasvideos.org, or ask on IRC: +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: [![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) From 577b46f350314f93518fcea045a17e61eaa7f181 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 01:43:21 +1000 Subject: [PATCH 087/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 280247c4af..284f193c3a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -tl;dr: click the "latest" button above to grab it. The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Don't mix versions**, copy `config.ini` to keep settings. +Click the "release" button above to grab the latest stable version. The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: * [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) From 54729d3c1533aeb435c85b9ed894db4d127710e1 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 01:48:13 +1000 Subject: [PATCH 088/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 284f193c3a..10f17bcb8d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -Click the "release" button above to grab the latest stable version. The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Never mix different versions** of BizHawk — Keep each version in its own folder. +Click the "release" button above to grab the latest stable version. New users on Windows will need [this](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: * [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) From 4bc924ebd495418824ab828ef23e5786d23c6fb6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 01:52:05 +1000 Subject: [PATCH 089/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 10f17bcb8d..9b23324ae8 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@ Jump to: ## Features The BizHawk common features (across all cores) are: -* rom format and region detection and a corruption check +* detection of game format and region, and corruption checking * 10 savestate slots and save/load to file * speed control, including frame stepping and rewinding * memory view/search/edit in all parts of the emulated HW * input recording (making TAS movies) -* take screenshots and record video +* screenshotting and recording video System | BH Common | Accuracy† | Debugging | Peripherals --:|:-:|:-:|:-:|:-: From 108879217f91510adf2e152fc47f44077436e4a3 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 01:53:32 +1000 Subject: [PATCH 090/440] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9b23324ae8..24f048b28f 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,10 @@ If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the s TODO +powershell to come + +something something IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community) + [Compiling](http://tasvideos.org/Bizhawk/Compiling.html) ### GNU+Linux and macOS From dd7abcd5dfe409cd99ee2b9fee43720f0fe06664 Mon Sep 17 00:00:00 2001 From: James Groom Date: Thu, 10 Jan 2019 16:06:37 +0000 Subject: [PATCH 091/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24f048b28f..1a177fc20e 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the s TODO -powershell to come +powershell *should* be `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`, but getting errors w/ master something something IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community) From e7b18c587139ffc5d473f2256becdb15c5e6d379 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 02:44:52 +1000 Subject: [PATCH 092/440] Update README.md --- README.md | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 1a177fc20e..58ff76e40b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) -[![unique systems emulated | 22](https://img.shields.io/badge/unique_systems_emulated-22-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) +[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). @@ -28,35 +28,20 @@ The BizHawk common features (across all cores) are: * memory view/search/edit in all parts of the emulated HW * input recording (making TAS movies) * screenshotting and recording video +* organised firmware +* input, framerate, and other overlays +* emulated controllers via a comprehensive input mapper +* Lua control over core and frontend (Windows only) -System | BH Common | Accuracy† | Debugging | Peripherals ---:|:-:|:-:|:-:|:-: -Apple II | ✓ | 95%? | ? | ? -Atari 2600 | ✓ | 95%? | ◕ | ? -Atari 7800 | ✓ | 95%? | ◕ | ? -Atari Lynx | ✓ | 95%? | ◔ | ? -ColecoVision | ✓ | 95%? | ◕ | ? -Commodore 64 | ✓ | 95%? | ◕ | [some](http://tasvideos.org/Bizhawk/C64.html) -GB/GBC | ✓ | 95%? | ✓ | ? -GBA | ✓ | 95%? | ◕ | ? -Genesis | ✓ | 95%? | ✓ | [all?](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) -IntelliVision | ✓ | 95%? | ◕ | ? -Master System | ✓ | 95%? | ✓ | ? -N64 | ✓ | 95%? | ◕ | [all?](http://tasvideos.org/Bizhawk/N64.html) -NGP/NGPC | ✓ | 95%? | ◔ | N/A -NES | ✓ | 95%? | ✓ | ? -PSX | ✓ | 95%? | ? | ? -Saturn | ✓ | 95%? | ◔ | ? -SNES | ✓ | 95%? | ✓ | ? -TI-83 | ✓ | 95%? | ? | N/A -PC Engine / SG | ✓ | 95%? | ✓ | ? -Virtual Boy | ✓ | 95%? | ? | N/A -WonderSwan | ✓ | 95%? | ◕ | N/A -ZX Spectrum | ✓ | 95%? | ✓ | [common](http://tasvideos.org/Bizhawk/ZXSpectrum.html) +Supported consoles and PCs: -† *approximately* what portion of games run perfectly, not counting romhacks/homebrew (if you want to count, go right ahead) - -EmuHawk's frontend also has a firmware manager, nice overlays, and a comprehensive input mapper. We're talking keyboard and controller mapped to one emulated controller, analog from digital and digital from analog, keyboard hotkeys, controller hotkeys, and rapid fire for emulated controllers. Most of the frontend can be controlled with Lua scripts (only on Windows for now). These scripts can draw overlays for casual play or for RTA speedruns, change the running game to add complex cheats, assist TASers and romhackers in debugging a game, and more. But most importantly: BizHawk is Hawk Biz. +* N64 and [all peripherals](http://tasvideos.org/Bizhawk/N64.html); Playstation (PSX); Saturn; Virtual Boy +* Game Boy Advance; Game Boy Color; Neo Geo Pocket (Color); WonderSwan (Color) +* Genesis and [all peripherals](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default); SNES; TurboGrafx / SuperGrafx +* Atari Lynx; Game Boy; Game Gear; TI-83 +* Atari 7800; Commodore 64 and [some peripherals](http://tasvideos.org/Bizhawk/C64.html); Master System; NES; ZX Spectrum and [some peripherals](http://tasvideos.org/Bizhawk/ZXSpectrum.html) +* Apple II; Atari 2600; ColecoVision; IntelliVision +* [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? See the *Usage* sections below for details about specific tools and config menus. @@ -183,8 +168,7 @@ If you'd like to add a feature, first search the issue tracker for it. If it's a * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform * [Dolphin](https://dolphin-emu.org) for GameCube and (original) Wii — cross-platform * [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run on Unix -* [Hourglass](https://github.com/TASVideos/hourglass-win32) for Windows Win32 — Windows-only, see also [rewrite project](https://github.com/Hourglass-Resurrection/Hourglass-Resurrection) -* [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only +* [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only, also emulates other emulators * [openMSX](https://openmsx.org) for MSX — cross-platform ## License From 506d9e2e0c77ba0821396d0594f04b685d328d7e Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:00:34 +1000 Subject: [PATCH 093/440] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58ff76e40b..26634d63c6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # BizHawk +[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) -[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) +[![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -Click the "release" button above to grab the latest stable version. New users on Windows will need [this](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest). The changelog is [here at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html). **Never mix different versions** of BizHawk — Keep each version in its own folder. +Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: * [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) From 5e3b2eada3164daf16254742c8db840737e201dc Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:04:07 +1000 Subject: [PATCH 094/440] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 26634d63c6..a5eeaae82f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ Jump to: ## Features The BizHawk common features (across all cores) are: -* detection of game format and region, and corruption checking +* format and region detection for game images +* image corruption warning checked against database * 10 savestate slots and save/load to file * speed control, including frame stepping and rewinding * memory view/search/edit in all parts of the emulated HW From d1f3b19c73194ceb978382fc0494f1ddb79bd3ec Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:05:27 +1000 Subject: [PATCH 095/440] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5eeaae82f..1d64f7edeb 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ The BizHawk common features (across all cores) are: Supported consoles and PCs: -* N64 and [all peripherals](http://tasvideos.org/Bizhawk/N64.html); Playstation (PSX); Saturn; Virtual Boy +* N64 and [all](http://tasvideos.org/Bizhawk/N64.html) peripherals; Playstation (PSX); Saturn; Virtual Boy * Game Boy Advance; Game Boy Color; Neo Geo Pocket (Color); WonderSwan (Color) -* Genesis and [all peripherals](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default); SNES; TurboGrafx / SuperGrafx +* Genesis and [all](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) peripherals; SNES; TurboGrafx / SuperGrafx * Atari Lynx; Game Boy; Game Gear; TI-83 -* Atari 7800; Commodore 64 and [some peripherals](http://tasvideos.org/Bizhawk/C64.html); Master System; NES; ZX Spectrum and [some peripherals](http://tasvideos.org/Bizhawk/ZXSpectrum.html) +* Atari 7800; Commodore 64 and [some](http://tasvideos.org/Bizhawk/C64.html) peripherals; Master System; NES; ZX Spectrum and [some](http://tasvideos.org/Bizhawk/ZXSpectrum.html) peripherals * Apple II; Atari 2600; ColecoVision; IntelliVision * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? From 47fe7743c8964438b54bc2869fb034c3135f7228 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:06:17 +1000 Subject: [PATCH 096/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d64f7edeb..d94c4c7805 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Jump to: * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) -## Features +## Features and systems The BizHawk common features (across all cores) are: * format and region detection for game images From 56c9033ef839bcfcbc9481f24e17b499f6df79bb Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:17:12 +1000 Subject: [PATCH 097/440] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d94c4c7805..086b9f805f 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,12 @@ Click the "release" button above to grab the latest stable version ([changelog a Jump to: * [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) * [Installing — GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--gnulinux-and-macos) -* [Building/Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#buildingtesting) +* [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) * [Usage (emulation)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-emulation) * [Usage (TASing)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-tasing) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) +* [Testing]() * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) @@ -165,6 +166,10 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. +### Testing + +Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. + ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From a2edf3646a216fd3236f863a615e0765d0c279a4 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:18:42 +1000 Subject: [PATCH 098/440] Update README.md --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 086b9f805f..3ea82587b9 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,15 @@ A multi-system emulator written in C#. As well as quality-of-life features for c Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: -* [Installing — Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--windows-78110) -* [Installing — GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing--gnulinux-and-macos) +* Installing + * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) + * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) * [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) -* [Usage (emulation)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-emulation) -* [Usage (TASing)](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage-tasing) +* [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) + * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) -* [Testing]() + * [Testing]() * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) @@ -48,7 +49,9 @@ Supported consoles and PCs: See the *Usage* sections below for details about specific tools and config menus. -## Installing — Windows 7/8.1/10 +## Installing + +### Windows 7/8.1/10 Released binaries can be found right here on GitHub: @@ -68,7 +71,7 @@ BizHawk functions like a "portable" program, you may move or rename the folder c Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). -## Installing — GNU+Linux and macOS +### GNU+Linux and macOS Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see TASVideos here](http://tasvideos.org/Bizhawk/ReleaseHistory.html). @@ -126,11 +129,11 @@ Once built, see the *Installing* section, substituting the repo's `output` folde Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). -## Usage (emulation) +## Usage TODO -## Usage (TASing) +### TASing This section refers to BizHawk specifically. For resources on TASing in general, see [Welcome to TASVideos](http://tasvideos.org/WelcomeToTASVideos.html). From 4ee836982a0f4f727cb6f2f86af834e80a2bbde5 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:20:50 +1000 Subject: [PATCH 099/440] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3ea82587b9..e67c4be4ee 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,7 @@ Dev builds are automated with AppVeyor, every green checkmark in the [commit his * [Dolphin](https://dolphin-emu.org) for GameCube and (original) Wii — cross-platform * [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run on Unix * [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only, also emulates other emulators +* [lsnes](http://tasvideos.org/Lsnes.html) for SNES — Windows-only * [openMSX](https://openmsx.org) for MSX — cross-platform ## License From 753a14ef1ec5b7b9229b9074594db111931f30e6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:26:07 +1000 Subject: [PATCH 100/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e67c4be4ee..10121d8935 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Install BizHawk with your distro's package manager. The package name is given on [![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABRUlEQVR4nO3bQUrDQBTG8Qdu3dS91r2CAzYE3Cm9QBURmjq7Yk9QIsELJYJ2XYqh7UJbL9NcYFyoGAQZiFMygf8Hb/vNm192IREhhJBS+ou4Fa3vM71Kitv3B1P3lHer2qFXSTFYJ2l/EbesANev46y7HJkw1yZ4GdQ+5d2qdoS5Nt3lyNy8xakV4Hw+LOq+tGuA77mY322sAL48+W0AhLk2f93b2SE+A/zuAwAAAAAAAAAAAAAAAAAAcH3IqcNpJMBWAkATAVy+E2wkgE9dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAZzrTaOPT0i67OtPI/suMyq6efVraZdfJ4+WTFWD3bP9Ypb1JMIsq/zzlHcAsKlTam+wFB0dWABHZEZFDEVHi4NO2f3S47FIi0v66GyHkJx/0rGTAdYdsEwAAAABJRU5ErkJggg==&style=popout)](https://aur.archlinux.org/packages/bizhawk) [![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) -If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). +If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See #1430 for progress. Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): @@ -94,7 +94,7 @@ Linux distros are supported if the distributor is still supporting your version, macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. -## Building/Testing +## Building If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download `BizHawk_Developer--#.zip`. From 4f53bb2d90dba292f1b07d13a2e73002e9ee7663 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:27:38 +1000 Subject: [PATCH 101/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 10121d8935..fcd66bb4e6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: -* Installing +* [Installing](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing) * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) * [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) @@ -18,7 +18,7 @@ Jump to: * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) - * [Testing]() + * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) From c44aed966f276f5096add4fc61ceb548b8eb02c3 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:28:48 +1000 Subject: [PATCH 102/440] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fcd66bb4e6..67dd936044 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,11 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. +Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). + +New users on Windows should click the "prereqs" button too, see *Installing* for info. + +**Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: * [Installing](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing) From ec65982893e1dd736ac8b1476b4f70ff65cf90c4 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:34:01 +1000 Subject: [PATCH 103/440] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 67dd936044..0370381083 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BizHawk -[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#features) +[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) @@ -20,6 +20,7 @@ Jump to: * [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) * [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) + * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) @@ -151,6 +152,12 @@ TODO [TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) +### Cores + +A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there's currently a bit of overlap in the cores BizHawk uses as noted below. + +TABLE GOES HERE + ## Support and troubleshooting A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: From b62abb7f0bfef23a933534f5c2bb13acd237fa9a Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:39:03 +1000 Subject: [PATCH 104/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0370381083..700874c633 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Jump to: The BizHawk common features (across all cores) are: * format and region detection for game images * image corruption warning checked against database -* 10 savestate slots and save/load to file +* 10 save slots with hotkeys and ∞ named savestates * speed control, including frame stepping and rewinding * memory view/search/edit in all parts of the emulated HW * input recording (making TAS movies) From d9836e0c20aba69c3bb0f450c38de87620868b26 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:45:48 +1000 Subject: [PATCH 105/440] Update README.md --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 700874c633..cbdd4b170a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # BizHawk +A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). + +*** + [![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) -A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). - Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. @@ -30,17 +32,17 @@ Jump to: ## Features and systems The BizHawk common features (across all cores) are: -* format and region detection for game images -* image corruption warning checked against database +* format, region, and integrity detection for game images * 10 save slots with hotkeys and ∞ named savestates * speed control, including frame stepping and rewinding -* memory view/search/edit in all parts of the emulated HW +* memory view/search/edit in all emulated hardware components * input recording (making TAS movies) * screenshotting and recording video -* organised firmware -* input, framerate, and other overlays +* firmware management +* input, framerate, and more in a HUD over the game * emulated controllers via a comprehensive input mapper * Lua control over core and frontend (Windows only) +* hotkey bindings to control the UI Supported consoles and PCs: From c1e2d2388c33f9117920af60ed4bb4be22781c17 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 03:55:46 +1000 Subject: [PATCH 106/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cbdd4b170a..8c5eb40362 100644 --- a/README.md +++ b/README.md @@ -37,14 +37,14 @@ The BizHawk common features (across all cores) are: * speed control, including frame stepping and rewinding * memory view/search/edit in all emulated hardware components * input recording (making TAS movies) -* screenshotting and recording video +* screenshotting and recording audio + video to file * firmware management * input, framerate, and more in a HUD over the game * emulated controllers via a comprehensive input mapper * Lua control over core and frontend (Windows only) * hotkey bindings to control the UI -Supported consoles and PCs: +Supported consoles and computers: * N64 and [all](http://tasvideos.org/Bizhawk/N64.html) peripherals; Playstation (PSX); Saturn; Virtual Boy * Game Boy Advance; Game Boy Color; Neo Geo Pocket (Color); WonderSwan (Color) From 9a9daf20d883c6b304336440d2f080532d6f125f Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 04:08:52 +1000 Subject: [PATCH 107/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c5eb40362..7129a8d5ab 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Is your distro not there? Released binaries can be found right here on GitHub (s If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -Linux distros are supported if the distributor is still supporting your version, you're using Linux 4.4/4.9/4.14/4.19 LTS or 4.20, and there are no updates available in your package manager. *Please* update and reboot. +Linux distros are supported if the distributor is still supporting your version, you're using Linux 4.4/4.9/4.14/4.19 LTS or 4.20 for x86_64/amd64, and there are no updates available in your package manager. *Please* update and reboot. macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. From 17a73c31e5bdb93eb31da0a560a52545902a9fab Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 04:18:34 +1000 Subject: [PATCH 108/440] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7129a8d5ab..70893026ae 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ The BizHawk common features (across all cores) are: Supported consoles and computers: -* N64 and [all](http://tasvideos.org/Bizhawk/N64.html) peripherals; Playstation (PSX); Saturn; Virtual Boy -* Game Boy Advance; Game Boy Color; Neo Geo Pocket (Color); WonderSwan (Color) -* Genesis and [all](https://bitbucket.org/eke/genesis-plus-gx/src/b573cd25853f9f8b5b941fc36506835e228144c6/wiki/Features.md?at=master&fileviewer=file-view-default) peripherals; SNES; TurboGrafx / SuperGrafx -* Atari Lynx; Game Boy; Game Gear; TI-83 -* Atari 7800; Commodore 64 and [some](http://tasvideos.org/Bizhawk/C64.html) peripherals; Master System; NES; ZX Spectrum and [some](http://tasvideos.org/Bizhawk/ZXSpectrum.html) peripherals +* N64; Playstation (PSX); Sega Saturn; Virtual Boy +* Game Boy Advance; Game Boy Color; Neo Geo Pocket / Color; WonderSwan / Color +* Sega Genesis; SNES; TurboGrafx / SuperGrafx +* Atari Lynx; Game Boy; Sega Game Gear; TI-83 +* Atari 7800; Commodore 64; Sega Master System; NES; ZX Spectrum * Apple II; Atari 2600; ColecoVision; IntelliVision * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? From e60be7753c8f8108ab5e540357d0d0819867a252 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 04:32:54 +1000 Subject: [PATCH 109/440] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 70893026ae..2ff79d35fd 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,11 @@ The BizHawk common features (across all cores) are: Supported consoles and computers: -* N64; Playstation (PSX); Sega Saturn; Virtual Boy -* Game Boy Advance; Game Boy Color; Neo Geo Pocket / Color; WonderSwan / Color -* Sega Genesis; SNES; TurboGrafx / SuperGrafx -* Atari Lynx; Game Boy; Sega Game Gear; TI-83 -* Atari 7800; Commodore 64; Sega Master System; NES; ZX Spectrum -* Apple II; Atari 2600; ColecoVision; IntelliVision +* N64; Playstation (PSX); Sega Saturn +* Game Boy; Game Boy Advance; Game Boy Color; Sega Game Gear +* Atari 2600; Atari 7800; Atari Lynx; NES; Sega Genesis; Sega Master System; SNES; Virtual Boy +* Apple II; Commodore 64; ColecoVision; IntelliVision; TurboGrafx / SuperGrafx; ZX Spectrum +* Neo Geo Pocket / Color; TI-83; WonderSwan / Color * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? See the *Usage* sections below for details about specific tools and config menus. From 5200ce89c63c3d14e75105a242238bd981d36068 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 18:07:44 +1000 Subject: [PATCH 110/440] Update README.md --- README.md | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2ff79d35fd..463aeaf465 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,30 @@ The BizHawk common features (across all cores) are: Supported consoles and computers: -* N64; Playstation (PSX); Sega Saturn -* Game Boy; Game Boy Advance; Game Boy Color; Sega Game Gear -* Atari 2600; Atari 7800; Atari Lynx; NES; Sega Genesis; Sega Master System; SNES; Virtual Boy -* Apple II; Commodore 64; ColecoVision; IntelliVision; TurboGrafx / SuperGrafx; ZX Spectrum -* Neo Geo Pocket / Color; TI-83; WonderSwan / Color +* Apple II +* Atari 2600 +* Atari 7800 +* Atari Lynx +* Commodore 64 +* ColecoVision +* Game Boy +* Game Boy Advance +* Game Boy Color +* IntelliVision +* N64 +* Neo Geo Pocket / Color +* NES +* Playstation (PSX) +* Sega Game Gear +* Sega Genesis +* Sega Master System +* Sega Saturn +* SNES +* TI-83 +* TurboGrafx / SuperGrafx +* Virtual Boy +* WonderSwan / Color +* ZX Spectrum * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? See the *Usage* sections below for details about specific tools and config menus. @@ -191,7 +210,7 @@ Dev builds are automated with AppVeyor, every green checkmark in the [commit his * [Dolphin](https://dolphin-emu.org) for GameCube and (original) Wii — cross-platform * [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run on Unix * [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only, also emulates other emulators -* [lsnes](http://tasvideos.org/Lsnes.html) for SNES — Windows-only +* [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform ## License From 79252ee41706a58f9baa12aadaa800e15c2456fc Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 18:25:16 +1000 Subject: [PATCH 111/440] Update README.md --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 463aeaf465..9bdd9c7d4e 100644 --- a/README.md +++ b/README.md @@ -127,13 +127,16 @@ If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the s ### Windows 7/8.1/10 -TODO +If you have WSL, Git BASH, or similar, clone the repo with: +``` +git clone https://github.com/TASVideos/BizHawk.git BizHawk_master +# or ssh: git clone git@github.com:TASVideos/BizHawk.git BizHawk_master +``` +...or use a [Git GUI](https://desktop.github.com). Otherwise, you'll have to download an archive from GitHub. -powershell *should* be `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`, but getting errors w/ master +On Windows 10, open a PowerShell window in BizHawk_master (Shift+Mouse2 in File Explorer) and run `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`. TODO: didn't work for me. On older versions, a similar Command Prompt script should work. -something something IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community) - -[Compiling](http://tasvideos.org/Bizhawk/Compiling.html) +The best free C# IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community), which you'll need to work on the project efficiently. Open `BizHawk.sln` with VS to start. ### GNU+Linux and macOS From 62363e3cded9cad0976c6498bf156e61943c29cc Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 18:26:27 +1000 Subject: [PATCH 112/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9bdd9c7d4e..f097779edf 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Jump to: * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) * [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) + * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) + * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) * [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) From 5905dc2d7c01a55c56b62c065b746f2e0b8d50be Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 19:45:36 +1000 Subject: [PATCH 113/440] Update README.md --- README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f097779edf..f9e7bd7f50 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,35 @@ TODO A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there's currently a bit of overlap in the cores BizHawk uses as noted below. -TABLE GOES HERE +System | Core | Alt. Core | SGB +--:|:--|:--|:-- +Amstrad CPC | CPCHawk† || +Apple II | Virtu || +Atari 2600 | Atari2600Hawk || +Atari 7800 | A7800Hawk || +Atari Lynx | Handy || +Commodore 64 | C64Hawk || +ColecoVision | ColecoHawk || +Game Boy | GBHawk | Gambatte | SameBoy (on SNES with SGB) +Game Boy Advance | mGBA/VBA-Next | mGBA/VBA-Next | +Game Boy Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) +IntelliVision | IntelliHawk || +N64 | Mupen64Plus || +Neo Geo Pocket / Color | NeoPop || +NES | NesHawk | QuickNes || +Playstation (PSX) | Octoshock || +Sega Game Gear | SMSHawk || +Sega Genesis | Genplus-gx || +Sega Master System | SMSHawk || +Sega Saturn | Saturnus || +SNES | BSNES/Snes9x | BSNES/Snes9x | +TI-83 | TI83Hawk || +TurboGrafx / SuperGrafx | PCEHawk || +Virtual Boy | Virtual Boyee || +WonderSwan / Color | Cygne || +ZX Spectrum | ZXHawk || + +† core is in development and unreleased ## Support and troubleshooting From 3794d0ced8063c106c6ad9918f98375c10705e5e Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 20:00:38 +1000 Subject: [PATCH 114/440] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9e7bd7f50..c4ffc3f253 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Supported consoles and computers: * N64 * Neo Geo Pocket / Color * NES +* PC-FX * Playstation (PSX) * Sega Game Gear * Sega Genesis @@ -181,7 +182,7 @@ TODO A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there's currently a bit of overlap in the cores BizHawk uses as noted below. -System | Core | Alt. Core | SGB +System | Core | Alt. Core | Special Core --:|:--|:--|:-- Amstrad CPC | CPCHawk† || Apple II | Virtu || @@ -194,10 +195,13 @@ Game Boy | GBHawk | Gambatte | SameBoy (on SNES with SGB) Game Boy Advance | mGBA/VBA-Next | mGBA/VBA-Next | Game Boy Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) IntelliVision | IntelliHawk || +Magnavox Odyssey² | O2Em† || N64 | Mupen64Plus || -Neo Geo Pocket / Color | NeoPop || +Neo Geo Pocket / Color | NeoPop || Dual NeoPop (dual instance) NES | NesHawk | QuickNes || +PC-FX | T.S.T. || Playstation (PSX) | Octoshock || +PSP | PPSSPP† || Sega Game Gear | SMSHawk || Sega Genesis | Genplus-gx || Sega Master System | SMSHawk || @@ -205,6 +209,7 @@ Sega Saturn | Saturnus || SNES | BSNES/Snes9x | BSNES/Snes9x | TI-83 | TI83Hawk || TurboGrafx / SuperGrafx | PCEHawk || +Uzebox | Uzem† || Virtual Boy | Virtual Boyee || WonderSwan / Color | Cygne || ZX Spectrum | ZXHawk || From 9c397a005384c82544399eb65a708ef0511436da Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 20:02:51 +1000 Subject: [PATCH 115/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c4ffc3f253..4e7a14df18 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Supported consoles and computers: * Sega Game Gear * Sega Genesis * Sega Master System +* Sega Pico * Sega Saturn * SNES * TI-83 @@ -206,6 +207,7 @@ Sega Game Gear | SMSHawk || Sega Genesis | Genplus-gx || Sega Master System | SMSHawk || Sega Saturn | Saturnus || +Sega Pico | PicoDrive || SNES | BSNES/Snes9x | BSNES/Snes9x | TI-83 | TI83Hawk || TurboGrafx / SuperGrafx | PCEHawk || From 48e9f731b2b12ddff2234d01ed84b52cfac18756 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 20:07:09 +1000 Subject: [PATCH 116/440] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4e7a14df18..16d0e75d4c 100644 --- a/README.md +++ b/README.md @@ -125,10 +125,6 @@ macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to ## Building -If you want to test the latest changes without building BizHawk yourself, grab the developer build from [AppVeyor](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history). Pick the topmost one that doesn't say "Pull request", then click "Artifacts" and download `BizHawk_Developer--#.zip`. - -If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as the main package. If it's available, installing it will automate the build process. - ### Windows 7/8.1/10 If you have WSL, Git BASH, or similar, clone the repo with: @@ -146,6 +142,8 @@ The best free C# IDE is [VS Community 2017](https://visualstudio.microsoft.com/v *Compiling* requires MSBuild and *running* requires Mono and WINE, but **BizHawk does not run under WINE** — only the bundled libraries are required. +If you use GNU+Linux, there might be a `bizhawk-git` package or similar in the same repo as the main package. If it's available, installing it will automate the build process. + Building is as easy as: ```sh git clone https://github.com/TASVideos/BizHawk.git BizHawk_master && cd BizHawk_master @@ -244,6 +242,8 @@ If you'd like to add a feature, first search the issue tracker for it. If it's a Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. +Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. + ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From 91b486e9a01eac3c709e85723f9ed922a1fb02b3 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 20:08:06 +1000 Subject: [PATCH 117/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16d0e75d4c..8245f0e1b8 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ New users on Windows should click the "prereqs" button too, see *Installing* for **Never mix different versions** of BizHawk — Keep each version in its own folder. Jump to: -* [Installing](https://github.com/TASVideos/BizHawk/blob/master/README.md#installing) +* Installing * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) -* [Building](https://github.com/TASVideos/BizHawk/blob/master/README.md#building) +* Building * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) * [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) From 13704e1904c35ed4b062c682694c1ba91651c0de Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 21:58:06 +1000 Subject: [PATCH 118/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8245f0e1b8..0b38029fe4 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,8 @@ BizHawk functions like a "portable" program, you may move or rename the folder c Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). +A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for Windows XP and 32-bit users. Being in the 1.x series, many bugs remain and features are missing. + ### GNU+Linux and macOS Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see TASVideos here](http://tasvideos.org/Bizhawk/ReleaseHistory.html). From 993a6d80e2ef7e57d2e72b815174f90727be89a6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:08:42 +1000 Subject: [PATCH 119/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0b38029fe4..ee6e8dd700 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,8 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. +Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. + ### Testing Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. From 0d71b4a525f03537c7838e56f8dbceaa960e75f0 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:10:10 +1000 Subject: [PATCH 120/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee6e8dd700..41fc7d613d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c *** -[![unique systems emulated | 24](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 26](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) From a48c697016c0910870e07b6b446c68fb66b7c8db Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:11:18 +1000 Subject: [PATCH 121/440] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 41fc7d613d..875e9b51bd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c *** -[![unique systems emulated | 26](https://img.shields.io/badge/unique_systems_emulated-24-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 25](https://img.shields.io/badge/unique_systems_emulated-25-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) @@ -54,9 +54,8 @@ Supported consoles and computers: * Atari Lynx * Commodore 64 * ColecoVision -* Game Boy +* Game Boy / Color * Game Boy Advance -* Game Boy Color * IntelliVision * N64 * Neo Geo Pocket / Color @@ -192,9 +191,8 @@ Atari 7800 | A7800Hawk || Atari Lynx | Handy || Commodore 64 | C64Hawk || ColecoVision | ColecoHawk || -Game Boy | GBHawk | Gambatte | SameBoy (on SNES with SGB) +Game Boy / Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) Game Boy Advance | mGBA/VBA-Next | mGBA/VBA-Next | -Game Boy Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) IntelliVision | IntelliHawk || Magnavox Odyssey² | O2Em† || N64 | Mupen64Plus || From 9cbf6455f86ff0cb84fc9fa0b1ee868ccf21c638 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:11:49 +1000 Subject: [PATCH 122/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 875e9b51bd..40a723442c 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -*** - [![unique systems emulated | 25](https://img.shields.io/badge/unique_systems_emulated-25-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) +*** + Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). New users on Windows should click the "prereqs" button too, see *Installing* for info. From dd69df3433d0c24847657c51ed1dd9d52669b0ae Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:14:13 +1000 Subject: [PATCH 123/440] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 40a723442c..3112449ec4 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ Linux distros are supported if the distributor is still supporting your version, macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Building ### Windows 7/8.1/10 @@ -160,6 +162,8 @@ Once built, see the *Installing* section, substituting the repo's `output` folde Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Usage TODO @@ -216,6 +220,8 @@ ZX Spectrum | ZXHawk || † core is in development and unreleased +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Support and troubleshooting A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: @@ -246,6 +252,8 @@ Dev builds are automated with AppVeyor, every green checkmark in the [commit his Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From 49fe45488177d920be59bdc992bca0f3b95d8f2d Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 11 Jan 2019 22:15:06 +1000 Subject: [PATCH 124/440] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 3112449ec4..f975129b71 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported f A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for Windows XP and 32-bit users. Being in the 1.x series, many bugs remain and features are missing. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ### GNU+Linux and macOS Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see TASVideos here](http://tasvideos.org/Bizhawk/ReleaseHistory.html). @@ -141,6 +143,8 @@ On Windows 10, open a PowerShell window in BizHawk_master (Shift+Mouse2 in File The best free C# IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community), which you'll need to work on the project efficiently. Open `BizHawk.sln` with VS to start. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ### GNU+Linux and macOS *Compiling* requires MSBuild and *running* requires Mono and WINE, but **BizHawk does not run under WINE** — only the bundled libraries are required. @@ -168,6 +172,8 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn TODO +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ### TASing This section refers to BizHawk specifically. For resources on TASing in general, see [Welcome to TASVideos](http://tasvideos.org/WelcomeToTASVideos.html). @@ -182,6 +188,8 @@ TODO [TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ### Cores A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there's currently a bit of overlap in the cores BizHawk uses as noted below. @@ -232,6 +240,8 @@ A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Contributing BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the MIT license, this is *optional*, just be careful with reusing cores as some have copyleft licenses. From 25115fd2937b88dc999bb16959ca45a67a2c7b03 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 00:33:19 +1000 Subject: [PATCH 125/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f975129b71..ec6f8de728 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,8 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. +For the time being, style is not enforced in PRs, only build success. Please use CRLF and tabs in new files. + Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. ### Testing From 31f28f466ad65e16e50ef60fc9effb920295e9a2 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 00:39:53 +1000 Subject: [PATCH 126/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec6f8de728..134129c8b1 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. -For the time being, style is not enforced in PRs, only build success. Please use CRLF and tabs in new files. +For the time being, style is not enforced in PRs, only build success. Please use CRLF, tabs, and [Allman braces](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) in new files. Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. From 08fdb101ddd782e709a099f60e6f1f0d75ee2f7e Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 00:40:18 +1000 Subject: [PATCH 127/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 134129c8b1..e62a28e8bf 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ It's a good idea to check if anyone is already working on an issue by asking on If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. -For the time being, style is not enforced in PRs, only build success. Please use CRLF, tabs, and [Allman braces](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) in new files. +For the time being, style is not enforced in PRs, only build success is. Please use CRLF, tabs, and [Allman braces](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) in new files. Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. From 99b4e7f4d8f9ed420b9e9ba9d041ffc4274f9383 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 01:45:15 +1000 Subject: [PATCH 128/440] Update README.md --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e62a28e8bf..449571ddec 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,6 @@ A *core* is what we call the smaller bits of software that emulate just one syst System | Core | Alt. Core | Special Core --:|:--|:--|:-- -Amstrad CPC | CPCHawk† || Apple II | Virtu || Atari 2600 | Atari2600Hawk || Atari 7800 | A7800Hawk || @@ -204,29 +203,26 @@ Atari Lynx | Handy || Commodore 64 | C64Hawk || ColecoVision | ColecoHawk || Game Boy / Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) -Game Boy Advance | mGBA/VBA-Next | mGBA/VBA-Next | +Game Boy Advance | mGBA | VBA-Next | IntelliVision | IntelliHawk || -Magnavox Odyssey² | O2Em† || N64 | Mupen64Plus || Neo Geo Pocket / Color | NeoPop || Dual NeoPop (dual instance) NES | NesHawk | QuickNes || PC-FX | T.S.T. || Playstation (PSX) | Octoshock || -PSP | PPSSPP† || Sega Game Gear | SMSHawk || Sega Genesis | Genplus-gx || Sega Master System | SMSHawk || Sega Saturn | Saturnus || Sega Pico | PicoDrive || -SNES | BSNES/Snes9x | BSNES/Snes9x | +SNES | BSNES | Snes9x | TI-83 | TI83Hawk || TurboGrafx / SuperGrafx | PCEHawk || -Uzebox | Uzem† || Virtual Boy | Virtual Boyee || WonderSwan / Color | Cygne || ZX Spectrum | ZXHawk || -† core is in development and unreleased +Amstrad CPC, Magnavox Odyssey², PSP, and Uzebox emulation is a work-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see *Support* below). [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From 6cca49f828f6413af7ae5cd72c1805bbd17b40a0 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 01:46:54 +1000 Subject: [PATCH 129/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 449571ddec..af81e69468 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ TODO ### Cores -A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there's currently a bit of overlap in the cores BizHawk uses as noted below. +A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there are a few alternative cores which are *faster and less accurate*. System | Core | Alt. Core | Special Core --:|:--|:--|:-- From 73bbd688940d23812a30bb7edbee84e4a7decb33 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 01:53:13 +1000 Subject: [PATCH 130/440] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af81e69468..001d287281 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -[![unique systems emulated | 25](https://img.shields.io/badge/unique_systems_emulated-25-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 26](https://img.shields.io/badge/unique_systems_emulated-26-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) @@ -70,6 +70,7 @@ Supported consoles and computers: * SNES * TI-83 * TurboGrafx / SuperGrafx +* Uzebox * Virtual Boy * WonderSwan / Color * ZX Spectrum @@ -218,11 +219,12 @@ Sega Pico | PicoDrive || SNES | BSNES | Snes9x | TI-83 | TI83Hawk || TurboGrafx / SuperGrafx | PCEHawk || +Uzebox | Uzem || Virtual Boy | Virtual Boyee || WonderSwan / Color | Cygne || ZX Spectrum | ZXHawk || -Amstrad CPC, Magnavox Odyssey², PSP, and Uzebox emulation is a work-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see *Support* below). +Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see *Support* below). [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From 2647fcb74b7db9deb00265dc3eacb92886952754 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 01:58:20 +1000 Subject: [PATCH 131/440] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 001d287281..3d4fec96df 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). -New users on Windows should click the "prereqs" button too, see *Installing* for info. +New users on Windows need an extra download, click the "prereqs" button to get that and see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. @@ -76,7 +76,7 @@ Supported consoles and computers: * ZX Spectrum * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? -See the *Usage* sections below for details about specific tools and config menus. +See [*Usage*](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) below for details about specific tools and config menus. ## Installing @@ -163,7 +163,7 @@ Remove the `/p:...` flag from MSBuild if you want debugging symbols. If your distro isn't listed under *Installing* above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -Once built, see the *Installing* section, substituting the repo's `output` folder for the download. +Once built, see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) above, substituting the repo's `output` folder for the download. Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). @@ -224,7 +224,7 @@ Virtual Boy | Virtual Boyee || WonderSwan / Color | Cygne || ZX Spectrum | ZXHawk || -Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see *Support* below). +Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see below). [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) @@ -248,7 +248,7 @@ If you'd like to fix bugs, check the issue tracker here on GitHub: [![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) -It's a good idea to check if anyone is already working on an issue by asking on IRC (see *Support* above). +It's a good idea to check if anyone is already working on an issue by asking on IRC (see [*Support*](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) above). If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. From a6cf78a8b56ad98c0cff587b372ee2db4afb9f8c Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:12:24 +1000 Subject: [PATCH 132/440] Update README.md --- README.md | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 3d4fec96df..39e34a2ad0 100644 --- a/README.md +++ b/README.md @@ -49,31 +49,35 @@ The BizHawk common features (across all cores) are: Supported consoles and computers: * Apple II -* Atari 2600 -* Atari 7800 -* Atari Lynx -* Commodore 64 -* ColecoVision -* Game Boy / Color -* Game Boy Advance -* IntelliVision -* N64 -* Neo Geo Pocket / Color -* NES -* PC-FX -* Playstation (PSX) -* Sega Game Gear -* Sega Genesis -* Sega Master System -* Sega Pico -* Sega Saturn -* SNES -* TI-83 -* TurboGrafx / SuperGrafx +* Atari + * 2600 + * 7800 + * Lynx +* Bandai WonderSwan + Color +* CBM Commodore 64 +* Coleco Industries ColecoVision +* Mattel IntelliVision +* NEC + * PC Engine / TurboGrafx-16 + SuperGrafx + CD + * PC-FX +* Neo Geo Pocket + Color +* Nintendo + * Famicom / Nintendo Entertainment System + * Game Boy + Color + * Game Boy Advance + * Nintendo 64 + * Super Famicom / Super Nintendo Entertainment System + * Virtual Boy +* Sega + * Game Gear + * Genesis + 32X + CD + * Master System + SG-1000 + * Pico + * Saturn +* Sinclair ZX Spectrum +* Sony Playstation / PSX +* Texas Instruments TI-83 * Uzebox -* Virtual Boy -* WonderSwan / Color -* ZX Spectrum * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? See [*Usage*](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) below for details about specific tools and config menus. From 1be46842819d63a23c6de8c528d1fb256afeecde Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:12:50 +1000 Subject: [PATCH 133/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39e34a2ad0..1445e6fcdc 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Supported consoles and computers: * PC-FX * Neo Geo Pocket + Color * Nintendo - * Famicom / Nintendo Entertainment System + * Famicom / Nintendo Entertainment System + FDS * Game Boy + Color * Game Boy Advance * Nintendo 64 From 2afb731e5e1f5503662145a0af751425f9ec72c6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:13:58 +1000 Subject: [PATCH 134/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1445e6fcdc..18f242b63a 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Supported consoles and computers: * Apple II * Atari - * 2600 + * Video Computer System / 2600 * 7800 * Lynx * Bandai WonderSwan + Color From b2386830e32010c037b3acef9943264c27d65eef Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:14:59 +1000 Subject: [PATCH 135/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18f242b63a..2c03677ae0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). -New users on Windows need an extra download, click the "prereqs" button to get that and see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) for info. +New user on Windows? Install the prerequisites first, click the "prereqs" button to get that and see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. From aba7a9dde512f08f6cec81f1a6a7f82f2eafe3cc Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:16:55 +1000 Subject: [PATCH 136/440] Update README.md --- README.md | 57 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2c03677ae0..5a6803cfaf 100644 --- a/README.md +++ b/README.md @@ -199,34 +199,35 @@ TODO A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there are a few alternative cores which are *faster and less accurate*. -System | Core | Alt. Core | Special Core ---:|:--|:--|:-- -Apple II | Virtu || -Atari 2600 | Atari2600Hawk || -Atari 7800 | A7800Hawk || -Atari Lynx | Handy || -Commodore 64 | C64Hawk || -ColecoVision | ColecoHawk || -Game Boy / Color | GBHawk | Gambatte | SameBoy (on SNES with SGB) -Game Boy Advance | mGBA | VBA-Next | -IntelliVision | IntelliHawk || -N64 | Mupen64Plus || -Neo Geo Pocket / Color | NeoPop || Dual NeoPop (dual instance) -NES | NesHawk | QuickNes || -PC-FX | T.S.T. || -Playstation (PSX) | Octoshock || -Sega Game Gear | SMSHawk || -Sega Genesis | Genplus-gx || -Sega Master System | SMSHawk || -Sega Saturn | Saturnus || -Sega Pico | PicoDrive || -SNES | BSNES | Snes9x | -TI-83 | TI83Hawk || -TurboGrafx / SuperGrafx | PCEHawk || -Uzebox | Uzem || -Virtual Boy | Virtual Boyee || -WonderSwan / Color | Cygne || -ZX Spectrum | ZXHawk || +System | Core | Alt. Core +--:|:--|:-- +Apple II | Virtu | +Atari 2600 | Atari2600Hawk | +Atari 7800 | A7800Hawk | +Atari Lynx | Handy | +Commodore 64 | C64Hawk | +ColecoVision | ColecoHawk | +Game Boy / Color | GBHawk | Gambatte +Game Boy Advance | mGBA | VBA-Next +IntelliVision | IntelliHawk | +N64 | Mupen64Plus | +Neo Geo Pocket / Color | NeoPop | +NES | NesHawk | QuickNes | +PC-FX | T.S.T. | +Playstation (PSX) | Octoshock | +Sega Game Gear | SMSHawk | +Sega Genesis | Genplus-gx | +Sega Master System | SMSHawk | +Sega Saturn | Saturnus | +Sega Pico | PicoDrive | +SNES | BSNES | Snes9x +Super Game Boy | BSNES | SameBoy +TI-83 | TI83Hawk | +TurboGrafx / SuperGrafx | PCEHawk | +Uzebox | Uzem | +Virtual Boy | Virtual Boyee | +WonderSwan / Color | Cygne | +ZX Spectrum | ZXHawk | Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see below). From 4643e2302877432facb2665dccf22e6199bdfc14 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:24:35 +1000 Subject: [PATCH 137/440] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a6803cfaf..9a485be01e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -[![unique systems emulated | 26](https://img.shields.io/badge/unique_systems_emulated-26-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 27](https://img.shields.io/badge/unique_systems_emulated-27-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) @@ -71,9 +71,10 @@ Supported consoles and computers: * Sega * Game Gear * Genesis + 32X + CD - * Master System + SG-1000 + * Master System * Pico * Saturn + * SG-1000 * Sinclair ZX Spectrum * Sony Playstation / PSX * Texas Instruments TI-83 From 56a834b75f562891d2a3ce0a2af35ff50df008d3 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 02:56:25 +1000 Subject: [PATCH 138/440] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9a485be01e..2ae334141f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Jump to: * Installing * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) +* [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * Building * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) @@ -27,7 +28,6 @@ Jump to: * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) - * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) @@ -134,6 +134,14 @@ macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +## Testing + +Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. + +Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. + +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Building ### Windows 7/8.1/10 @@ -262,14 +270,6 @@ For the time being, style is not enforced in PRs, only build success is. Please Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. -### Testing - -Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. - -Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. - -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) - ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From 119b4058ebd430a844fd9e930764b3fa19a6961c Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Sat, 12 Jan 2019 15:13:48 +1000 Subject: [PATCH 139/440] Revert "Update README.md" This reverts commit 56a834b75f562891d2a3ce0a2af35ff50df008d3. --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2ae334141f..9a485be01e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ Jump to: * Installing * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) -* [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * Building * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) @@ -28,6 +27,7 @@ Jump to: * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) + * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) @@ -134,14 +134,6 @@ macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) -## Testing - -Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. - -Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. - -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) - ## Building ### Windows 7/8.1/10 @@ -270,6 +262,14 @@ For the time being, style is not enforced in PRs, only build success is. Please Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. +### Testing + +Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. + +Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. + +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From 37b1d999218399bc57058ad117aeb268847c799c Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 17:40:10 +1000 Subject: [PATCH 140/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9a485be01e..7a268ec8f5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Jump to: The BizHawk common features (across all cores) are: * format, region, and integrity detection for game images -* 10 save slots with hotkeys and ∞ named savestates +* 10 save slots with hotkeys and infinite named savestates * speed control, including frame stepping and rewinding * memory view/search/edit in all emulated hardware components * input recording (making TAS movies) @@ -248,7 +248,7 @@ If there's no easy solution, what you've got is a bug. Or maybe a feature reques ## Contributing -BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the MIT license, this is *optional*, just be careful with reusing cores as some have copyleft licenses. +BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the permissive *MIT license*, this is optional, just be careful with reusing cores as some have copyleft licenses. If you'd like to fix bugs, check the issue tracker here on GitHub: From 33ac41d8b8238e9cfd4434627cbc095cd484b490 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 17:40:26 +1000 Subject: [PATCH 141/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a268ec8f5..33644089c5 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,7 @@ If there's no easy solution, what you've got is a bug. Or maybe a feature reques ## Contributing -BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the permissive *MIT license*, this is optional, just be careful with reusing cores as some have copyleft licenses. +BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the permissive *MIT License*, this is optional, just be careful with reusing cores as some have copyleft licenses. If you'd like to fix bugs, check the issue tracker here on GitHub: From 5d1ca826c4735c61d6f7e8b010e1477e474f1289 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sat, 12 Jan 2019 18:06:19 +1000 Subject: [PATCH 142/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 33644089c5..7f48e33775 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,8 @@ Once you're on the build page, click "Artifacts" and download `BizHawk_Developer * [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform +The [TASVideos org](https://github.com/TASVideos) has some forks of other emulators and plugins. + ## License From the [full text](https://github.com/TASVideos/BizHawk/blob/master/LICENSE): From 9fdeb9f5eb5639bd73907986a4d3dd5c72df9c2b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Jan 2019 08:12:21 -0600 Subject: [PATCH 143/440] SubNESHawk: fix gambatte frameadvancepost, allow ppuviewer and nametableviewer --- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 4 +- .../Consoles/Nintendo/NES/NES.Core.cs | 2 +- .../Nintendo/SubNESHawk/SubNESHawk.cs | 106 +++++++++++++++++- 3 files changed, 107 insertions(+), 5 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index b0bdd405d9..1f1891e1a5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy LibGambatte.gambatte_setlayers(GambatteState, (_settings.DisplayBG ? 1 : 0) | (_settings.DisplayOBJ ? 2 : 0) | (_settings.DisplayWindow ? 4 : 0)); } - internal bool FrameAdvancePost() + internal void FrameAdvancePost() { if (IsLagFrame) { @@ -352,8 +352,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } endofframecallback?.Invoke(LibGambatte.gambatte_cpuread(GambatteState, 0xff40)); - - return true; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 851291e2a1..6ff0282779 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -31,7 +31,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int cpuclockrate { get; private set; } //user configuration - int[] palette_compiled = new int[64 * 8]; + public int[] palette_compiled = new int[64 * 8]; //variable set when VS system games are running internal bool _isVS = false; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index a04a68f7f8..91d590f508 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk isReleased: false)] [ServiceNotApplicable(typeof(IDriveLight))] public partial class SubNESHawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, - ISettable + ISettable, INESPPUViewable { public NES.NES subnes; @@ -76,5 +76,109 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk { MemoryCallbacks.CallExecutes(addr, "System Bus"); } + + #region PPU Viewable + + public int[] GetPalette() + { + return subnes.palette_compiled; + } + + public bool BGBaseHigh + { + get { return subnes.ppu.reg_2000.bg_pattern_hi; } + } + + public bool SPBaseHigh + { + get { return subnes.ppu.reg_2000.obj_pattern_hi; } + } + + public bool SPTall + { + get { return subnes.ppu.reg_2000.obj_size_16; } + } + + public byte[] GetPPUBus() + { + byte[] ret = new byte[0x3000]; + for (int i = 0; i < 0x3000; i++) + { + ret[i] = subnes.ppu.ppubus_peek(i); + } + return ret; + } + + public byte[] GetPalRam() + { + return subnes.ppu.PALRAM; + } + + public byte[] GetOam() + { + return subnes.ppu.OAM; + } + + public byte PeekPPU(int addr) + { + return subnes.Board.PeekPPU(addr); + } + + public byte[] GetExTiles() + { + if (subnes.Board is ExROM) + { + return subnes.Board.VROM ?? subnes.Board.VRAM; + } + else + { + throw new InvalidOperationException(); + } + } + + public bool ExActive + { + get { return subnes.Board is ExROM && (subnes.Board as ExROM).ExAttrActive; } + } + + public byte[] GetExRam() + { + if (subnes.Board is ExROM) + { + return (subnes.Board as ExROM).GetExRAMArray(); + } + else + { + throw new InvalidOperationException(); + } + } + + public MemoryDomain GetCHRROM() + { + return _memoryDomains["CHR VROM"]; + } + + + public void InstallCallback1(Action cb, int sl) + { + subnes.ppu.NTViewCallback = new PPU.DebugCallback { Callback = cb, Scanline = sl }; + } + + public void InstallCallback2(Action cb, int sl) + { + subnes.ppu.PPUViewCallback = new PPU.DebugCallback { Callback = cb, Scanline = sl }; + } + + public void RemoveCallback1() + { + subnes.ppu.NTViewCallback = null; + } + + public void RemoveCallback2() + { + subnes.ppu.PPUViewCallback = null; + } + + #endregion } } From 5256284ac682158000e2b85736e27b67422ee967 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Jan 2019 09:32:01 -0600 Subject: [PATCH 144/440] SubNESHawk: - Use NES settings for controllers / sync settings - Clean up un-needed extra controller code - Enable Menues --- BizHawk.Client.EmuHawk/MainForm.Events.cs | 9 + .../config/NES/NESGraphicsConfig.cs | 25 ++- .../config/NES/NesControllerSettings.cs | 11 +- .../BizHawk.Emulation.Cores.csproj | 163 +++++++++--------- .../Consoles/Nintendo/NES/NES.Core.cs | 56 +----- .../Consoles/Nintendo/NES/NES.IStatable.cs | 5 - .../SubNESHawk/SubNESHawk.IEmulator.cs | 23 +-- .../SubNESHawk/SubNESHawk.ISettable.cs | 58 ------- .../SubNESHawk/SubNESHawk.IStatable.cs | 4 - .../Nintendo/SubNESHawk/SubNESHawk.cs | 64 +++++-- .../SubNESHawk/SubNESHawkControllerDeck.cs | 89 ---------- .../SubNESHawk/SubNESHawkControllers.cs | 94 ---------- 12 files changed, 183 insertions(+), 418 deletions(-) delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs delete mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index f524b4bb13..1475a7e2dd 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -10,6 +10,7 @@ using BizHawk.Emulation.Cores.Atari.A7800Hawk; using BizHawk.Emulation.Cores.Calculators; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; using BizHawk.Emulation.Cores.Nintendo.N64; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.SNES9X; @@ -1634,6 +1635,10 @@ namespace BizHawk.Client.EmuHawk { new NESGraphicsConfig().ShowDialog(this); } + else if (Emulator is SubNESHawk) + { + new NESGraphicsConfig().ShowDialog(this); + } else if (Emulator is QuickNES) { new QuickNesConfig().ShowDialog(this); @@ -1704,6 +1709,10 @@ namespace BizHawk.Client.EmuHawk { new NesControllerSettings().ShowDialog(); } + else if (Emulator is SubNESHawk) + { + new NesControllerSettings().ShowDialog(); + } else if (Emulator is QuickNES) { GenericCoreConfig.DoDialog(this, "QuickNES Controller Settings", true, false); diff --git a/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs b/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs index f8c41e16ee..64b371ddc6 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESGraphicsConfig.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using BizHawk.Common; using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; namespace BizHawk.Client.EmuHawk { @@ -15,6 +16,7 @@ namespace BizHawk.Client.EmuHawk // Hotkeys for BG & Sprite display toggle // NTSC filter settings? Hue, Tint (This should probably be a client thing, not a nes specific thing?) private NES _nes; + private SubNESHawk _subneshawk; private NES.NESSettings _settings; private Bitmap _bmp; @@ -25,8 +27,17 @@ namespace BizHawk.Client.EmuHawk private void NESGraphicsConfig_Load(object sender, EventArgs e) { - _nes = (NES)Global.Emulator; - _settings = _nes.GetSettings(); + if (Global.Emulator is NES) + { + _nes = (NES)Global.Emulator; + _settings = _nes.GetSettings(); + } + else + { + _subneshawk = (SubNESHawk)Global.Emulator; + _settings = _subneshawk.GetSettings(); + } + LoadStuff(); } @@ -146,7 +157,15 @@ namespace BizHawk.Client.EmuHawk _settings.BackgroundColor &= 0x00FFFFFF; } - _nes.PutSettings(_settings); + if (Global.Emulator is NES) + { + _nes.PutSettings(_settings); + } + else + { + _subneshawk.PutSettings(_settings); + } + Close(); } diff --git a/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs b/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs index 068711825f..4141bf067e 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NesControllerSettings.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; namespace BizHawk.Client.EmuHawk { @@ -14,7 +15,15 @@ namespace BizHawk.Client.EmuHawk public NesControllerSettings() { InitializeComponent(); - _syncSettings = ((NES)Global.Emulator).GetSyncSettings(); + if (Global.Emulator is NES) + { + _syncSettings = ((NES)Global.Emulator).GetSyncSettings(); + } + else + { + _syncSettings = ((SubNESHawk)Global.Emulator).GetSyncSettings(); + } + // TODO: use combobox extension and add descriptions to enum values comboBoxFamicom.Items.AddRange(NESControlSettings.GetFamicomExpansionValues().ToArray()); diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index dda627b813..f6bf415a2a 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -317,9 +317,9 @@ - + - + @@ -327,23 +327,23 @@ - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + - NECUPD765.cs - + NECUPD765.cs + @@ -375,93 +375,93 @@ - SpectrumBase.cs - + SpectrumBase.cs + - SpectrumBase.cs - + SpectrumBase.cs + - SpectrumBase.cs - - - SpectrumBase.cs - - - - + SpectrumBase.cs + + + SpectrumBase.cs + + + + - ZX48.cs - - - ZX48.cs - + ZX48.cs + + + ZX48.cs + - - + + - ZX128.cs - + ZX128.cs + - ZX128.cs - + ZX128.cs + - - + + - ZX128Plus2a.cs - + ZX128Plus2a.cs + - ZX128Plus2a.cs - - - + ZX128Plus2a.cs + + + - ZX128Plus3.cs - + ZX128Plus3.cs + - ZX128Plus3.cs - + ZX128Plus3.cs + - Pentagon128.cs - + Pentagon128.cs + - Pentagon128.cs - - - - + Pentagon128.cs + + + + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - + ZXSpectrum.cs + - ZXSpectrum.cs - - - ZXSpectrum.cs - + ZXSpectrum.cs + + + ZXSpectrum.cs + Atari2600.cs @@ -789,7 +789,7 @@ VBANext.cs - + GBHawkLink.cs @@ -1201,7 +1201,7 @@ - + SubNESHawk.cs @@ -1217,14 +1217,9 @@ SubNESHawk.cs - - SubNESHawk.cs - SubNESHawk.cs - - diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 6ff0282779..40d3106894 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -419,17 +419,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public bool current_strobe; public bool new_strobe; public bool alt_lag; - public byte ctrl_1 = 0; - public byte ctrl_2 = 0; - public byte ctrl_1_new = 0; - public byte ctrl_2_new = 0; - public int shift_1; - public int shift_2; - public bool use_sub_input = false; // this function will run one step of the ppu // it will return whether the controller is read or not. - public void do_single_step(out bool cont_read, out bool frame_done) + public void do_single_step(IController controller, out bool cont_read, out bool frame_done) { + _controller = controller; + controller_was_latched = false; frame_is_done = false; @@ -779,21 +774,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { controller_was_latched = true; alt_lag = false; - - if (use_sub_input) - { - shift_1 = 7; - shift_2 = 7; - - ctrl_1 = ctrl_1_new; - ctrl_2 = ctrl_2_new; - } - } - - if (use_sub_input && new_strobe) - { - shift_1 = 7; - shift_2 = 7; } } @@ -803,36 +783,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES lagged = false; byte ret = 0; - if (use_sub_input) + if (_isVS) { - if (addr == 0x4016) - { - if (shift_1 >= 0) { ret = (byte)((ctrl_1 >> shift_1) & 1); } - else { ret = 1; } - - if (!current_strobe) { shift_1 -= 1; } - } - else - { - if (shift_2 >= 0) { ret = (byte)((ctrl_2 >> shift_2) & 1); } - else { ret = 1; } - - if (!current_strobe) { shift_2 -= 1; } - } + // for whatever reason, in VS left and right controller have swapped regs + ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); } else { - if (_isVS) - { - // for whatever reason, in VS left and right controller have swapped regs - ret = addr == 0x4017 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); - } - else - { - ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); - } + ret = addr == 0x4016 ? ControllerDeck.ReadA(_controller) : ControllerDeck.ReadB(_controller); } - + ret &= 0x1f; ret |= (byte)(0xe0 & DB); return ret; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs index 7c7b3f7f17..eeda0a5fd7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs @@ -85,11 +85,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // single cycle execution related ser.Sync("current_strobe", ref current_strobe); ser.Sync("new_strobe", ref new_strobe); - ser.Sync("ctrl_1", ref ctrl_1); - ser.Sync("ctrl_2", ref ctrl_2); - ser.Sync("shift_1", ref shift_1); - ser.Sync("shift_2", ref shift_2); - ser.Sync("use_sub_input", ref use_sub_input); ser.BeginSection("Board"); Board.SyncState(ser); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs index 3fef3f0d45..5e31027258 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk { public IEmulatorServiceProvider ServiceProvider { get; } - public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + public ControllerDefinition ControllerDefinition => subnes.ControllerDefinition; public bool FrameAdvance(IController controller, bool render, bool rendersound) { @@ -38,9 +38,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk _islag = true; subnes.alt_lag = true; - GetControllerState(controller); + InputCallbacks.Call(); - do_frame(); + do_frame(controller); bool ret = pass_a_frame; @@ -62,31 +62,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk public bool stop_cur_frame; public bool pass_new_input; public bool pass_a_frame; - public byte ctrl_byte_1; - public byte ctrl_byte_2; - public void do_frame() + public void do_frame(IController controller) { stop_cur_frame = false; while (!stop_cur_frame) { - subnes.do_single_step(out pass_new_input, out pass_a_frame); + subnes.do_single_step(controller, out pass_new_input, out pass_a_frame); stop_cur_frame |= pass_a_frame; stop_cur_frame |= pass_new_input; } } - public void GetControllerState(IController controller) - { - InputCallbacks.Call(); - - ctrl_byte_1 = _controllerDeck.ReadPort1(controller); - ctrl_byte_2 = _controllerDeck.ReadPort2(controller); - - subnes.ctrl_1_new = ctrl_byte_1; - subnes.ctrl_2_new = ctrl_byte_2; - } - public int Frame => _frame; public string SystemId => "NES"; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs deleted file mode 100644 index 9db3f0acc1..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.ISettable.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Nintendo.NES; - -namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk -{ - public partial class SubNESHawk : IEmulator, IStatable, ISettable - { - public SubNESHawkSettings GetSettings() - { - return subnesSettings.Clone(); - } - - public SubNESHawkSyncSettings GetSyncSettings() - { - return subnesSyncSettings.Clone(); - } - - public bool PutSettings(SubNESHawkSettings o) - { - subnesSettings = o; - return false; - } - - public bool PutSyncSettings(SubNESHawkSyncSettings o) - { - bool ret = SubNESHawkSyncSettings.NeedsReboot(subnesSyncSettings, o); - subnesSyncSettings = o; - return ret; - } - - private SubNESHawkSettings subnesSettings = new SubNESHawkSettings(); - public SubNESHawkSyncSettings subnesSyncSettings = new SubNESHawkSyncSettings(); - - public class SubNESHawkSettings - { - public SubNESHawkSettings Clone() - { - return (SubNESHawkSettings)MemberwiseClone(); - } - } - - public class SubNESHawkSyncSettings - { - public SubNESHawkSyncSettings Clone() - { - return (SubNESHawkSyncSettings)MemberwiseClone(); - } - - public static bool NeedsReboot(SubNESHawkSyncSettings x, SubNESHawkSyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs index d6a092971e..0f6a4b3e54 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs @@ -54,10 +54,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk ser.Sync("IsLag", ref _islag); ser.Sync("pass_a_frame", ref pass_a_frame); ser.Sync("pass_new_input", ref pass_new_input); - ser.Sync("ctrl_byte_1", ref ctrl_byte_1); - ser.Sync("ctrl_byte_2", ref ctrl_byte_2); - - _controllerDeck.SyncState(ser); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index 91d590f508..90b3904778 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk isReleased: false)] [ServiceNotApplicable(typeof(IDriveLight))] public partial class SubNESHawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, - ISettable, INESPPUViewable + ISettable, INESPPUViewable { public NES.NES subnes; @@ -22,18 +22,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk { var ser = new BasicServiceProvider(this); - subnesSettings = (SubNESHawkSettings)settings ?? new SubNESHawkSettings(); - subnesSyncSettings = (SubNESHawkSyncSettings)syncSettings ?? new SubNESHawkSyncSettings(); - _controllerDeck = new SubNESHawkControllerDeck(SubNESHawkControllerDeck.DefaultControllerName, SubNESHawkControllerDeck.DefaultControllerName); + subnesSettings = (NES.NES.NESSettings)settings ?? new NES.NES.NESSettings(); + subnesSyncSettings = (NES.NES.NESSyncSettings)syncSettings ?? new NES.NES.NESSyncSettings(); CoreComm = comm; - var temp_set = new NES.NES.NESSettings(); - - var temp_sync = new NES.NES.NESSyncSettings(); - subnes = new NES.NES(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, - game, rom, temp_set, temp_sync); + game, rom, subnesSettings, subnesSyncSettings); ser.Register(subnes.videoProvider); ser.Register(subnes.magicSoundProvider); @@ -46,9 +41,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk SetupMemoryDomains(); HardReset(); - - // input override for subframe input - subnes.use_sub_input = true; } public void HardReset() @@ -68,8 +60,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk public int _frame = 0; - private readonly SubNESHawkControllerDeck _controllerDeck; - private readonly ITraceable _tracer; private void ExecFetch(ushort addr) @@ -77,6 +67,52 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk MemoryCallbacks.CallExecutes(addr, "System Bus"); } + #region ISettable + private NES.NES.NESSettings subnesSettings = new NES.NES.NESSettings(); + public NES.NES.NESSyncSettings subnesSyncSettings = new NES.NES.NESSyncSettings(); + + public NES.NES.NESSettings GetSettings() + { + return subnesSettings.Clone(); + } + + public NES.NES.NESSyncSettings GetSyncSettings() + { + return subnesSyncSettings.Clone(); + } + + public bool PutSettings(NES.NES.NESSettings o) + { + subnesSettings = o; + if (subnesSettings.ClipLeftAndRight) + { + subnes.videoProvider.left = 8; + subnes.videoProvider.right = 247; + } + else + { + subnes.videoProvider.left = 0; + subnes.videoProvider.right = 255; + } + + CoreComm.ScreenLogicalOffsetX = subnes.videoProvider.left; + CoreComm.ScreenLogicalOffsetY = Region == DisplayType.NTSC ? subnesSettings.NTSC_TopLine : subnesSettings.PAL_TopLine; + + subnes.SetPalette(subnesSettings.Palette); + + subnes.apu.m_vol = subnesSettings.APU_vol; + + return false; + } + + public bool PutSyncSettings(NES.NES.NESSyncSettings o) + { + bool ret = NES.NES.NESSyncSettings.NeedsReboot(subnesSyncSettings, o); + subnesSyncSettings = o; + return ret; + } + #endregion + #region PPU Viewable public int[] GetPalette() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs deleted file mode 100644 index 7f2ecfae40..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllerDeck.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk -{ - public class SubNESHawkControllerDeck - { - public SubNESHawkControllerDeck(string controller1Name, string controller2Name) - { - if (!ValidControllerTypes.ContainsKey(controller1Name)) - { - throw new InvalidOperationException("Invalid controller type: " + controller1Name); - } - - if (!ValidControllerTypes.ContainsKey(controller2Name)) - { - throw new InvalidOperationException("Invalid controller type: " + controller2Name); - } - - Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); - Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2); - - Definition = new ControllerDefinition - { - Name = Port1.Definition.Name, - BoolButtons = Port1.Definition.BoolButtons - .Concat(Port2.Definition.BoolButtons) - .Concat(new[] - { - "Power", - "Reset", - }) - .ToList() - }; - } - - public byte ReadPort1(IController c) - { - return Port1.Read(c); - } - - public byte ReadPort2(IController c) - { - return Port2.Read(c); - } - - public ControllerDefinition Definition { get; } - - public void SyncState(Serializer ser) - { - ser.BeginSection("Port1"); - Port1.SyncState(ser); - ser.EndSection(); - - ser.BeginSection("Port2"); - Port2.SyncState(ser); - ser.EndSection(); - } - - private readonly IPort Port1; - private readonly IPort Port2; - - private static Dictionary _controllerTypes; - - public static Dictionary ValidControllerTypes - { - get - { - if (_controllerTypes == null) - { - _controllerTypes = typeof(SubNESHawkControllerDeck).Assembly - .GetTypes() - .Where(t => typeof(IPort).IsAssignableFrom(t)) - .Where(t => !t.IsAbstract && !t.IsInterface) - .ToDictionary(tkey => tkey.DisplayName()); - } - - return _controllerTypes; - } - } - - public static string DefaultControllerName => typeof(StandardControls).DisplayName(); - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs deleted file mode 100644 index 44e9e5e98d..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawkControllers.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; - -using System.ComponentModel; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk -{ - /// - /// Represents a Standard Nintendo Controller - /// - public interface IPort - { - byte Read(IController c); - - ControllerDefinition Definition { get; } - - void SyncState(Serializer ser); - - int PortNum { get; } - } - - [DisplayName("NES Controller")] - public class StandardControls : IPort - { - public StandardControls(int portNum) - { - PortNum = portNum; - Definition = new ControllerDefinition - { - Name = "NES Controller", - BoolButtons = BaseDefinition - .Select(b => "P" + PortNum + " " + b) - .ToList() - }; - } - - public int PortNum { get; } - - public ControllerDefinition Definition { get; } - - public byte Read(IController c) - { - byte result = 0; - - if (c.IsPressed(Definition.BoolButtons[0])) - { - result |= 8; - } - if (c.IsPressed(Definition.BoolButtons[1])) - { - result |= 4; - } - if (c.IsPressed(Definition.BoolButtons[2])) - { - result |= 2; - } - if (c.IsPressed(Definition.BoolButtons[3])) - { - result |= 1; - } - if (c.IsPressed(Definition.BoolButtons[4])) - { - result |= 16; - } - if (c.IsPressed(Definition.BoolButtons[5])) - { - result |= 32; - } - if (c.IsPressed(Definition.BoolButtons[6])) - { - result |= 64; - } - if (c.IsPressed(Definition.BoolButtons[7])) - { - result |= 128; - } - - return result; - } - - private static readonly string[] BaseDefinition = - { - "Up", "Down", "Left", "Right", "Start", "Select", "B", "A" - }; - - public void SyncState(Serializer ser) - { - //nothing - } - } -} \ No newline at end of file From f16c538872811fac88fce53855eb998ac58d4952 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 01:47:37 +1000 Subject: [PATCH 145/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f48e33775..8085b8e439 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ Once you're on the build page, click "Artifacts" and download `BizHawk_Developer * [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform -The [TASVideos org](https://github.com/TASVideos) has some forks of other emulators and plugins. +Emulators for other systems can be found on the [EmulatorResources page](http://tasvideos.org/EmulatorResources.html) at TASVideos. The [TASVideos org](https://github.com/TASVideos) also houses other emulators and plugins where development happens sometimes, their upstreams may be of use. ## License From 40928ad5ac953f81abcb5a504192dad79e317dbb Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 01:57:06 +1000 Subject: [PATCH 146/440] Update README.md --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8085b8e439..64e0ea4353 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ Jump to: * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) * [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) + * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) * [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) * [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) - * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) * [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) * [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) @@ -196,6 +196,16 @@ TODO [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +### Testing + +Testing bugfixes or new features can be just as helpful as making them! If code's more your thing, see [*Contributing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) below. + +Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. + +Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. + +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ### Cores A *core* is what we call the smaller bits of software that emulate just one system or family of systems, e.g. NES/Famicom. For the most part, there's a "best" core for each system, based on accuracy, but there are a few alternative cores which are *faster and less accurate*. @@ -250,6 +260,8 @@ If there's no easy solution, what you've got is a bug. Or maybe a feature reques BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the permissive *MIT License*, this is optional, just be careful with reusing cores as some have copyleft licenses. +Not a programmer? Something as simple as reproducing bugs with different software versions is still very helpful! See [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) above to learn about dev builds if you'd rather help us get the next release out. + If you'd like to fix bugs, check the issue tracker here on GitHub: [![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) @@ -262,14 +274,6 @@ For the time being, style is not enforced in PRs, only build success is. Please Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. -### Testing - -Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. - -Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. - -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) - ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From e80a5779ce22fdf53c7c3e1897fdb8cf6e089eb6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 02:14:51 +1000 Subject: [PATCH 147/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64e0ea4353..558d71de2c 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ Past contrbutors to the frontend and custom-built cores are listed [here](https: * [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform -Emulators for other systems can be found on the [EmulatorResources page](http://tasvideos.org/EmulatorResources.html) at TASVideos. The [TASVideos org](https://github.com/TASVideos) also houses other emulators and plugins where development happens sometimes, their upstreams may be of use. +Emulators for other systems can be found on the [EmulatorResources page](http://tasvideos.org/EmulatorResources.html) at TASVideos. The [TASVideos GitHub page](https://github.com/TASVideos) also houses other emulators and plugins where development happens sometimes, their upstreams may be of use. ## License From c5cfe9e412938c7c254c6cd7945d886417783713 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Jan 2019 10:41:50 -0600 Subject: [PATCH 148/440] SubNESHawk: Fix up FPS viewer --- BizHawk.Client.EmuHawk/MainForm.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index a7a40b17aa..b80c40533a 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2950,10 +2950,6 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.UpdateToolsBefore(); } - _framesSinceLastFpsUpdate++; - - UpdateFpsDisplay(currentTimestamp, isRewinding, isFastForwarding); - CaptureRewind(isRewinding); // Set volume, if enabled @@ -3041,6 +3037,13 @@ namespace BizHawk.Client.EmuHawk AvFrameAdvance(); } + if (new_frame) + { + _framesSinceLastFpsUpdate++; + + UpdateFpsDisplay(currentTimestamp, isRewinding, isFastForwarding); + } + if (GlobalWin.Tools.IsLoaded() && GlobalWin.Tools.TAStudio.LastPositionFrame == Emulator.Frame) { From 74d20ca45cd7d4c19c979e68e60d019b28637fb9 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Jan 2019 13:27:00 -0600 Subject: [PATCH 149/440] SubNEShawk: Add VBL Count to BK2 movie header --- BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs | 6 ++++++ .../movie/conversions/MovieConversionExtensions.cs | 6 ++++++ .../Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs | 1 + .../Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs | 1 + .../Consoles/Nintendo/SubNESHawk/SubNESHawk.cs | 5 +++++ 5 files changed, 19 insertions(+) diff --git a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs index f56331b533..c7d63a4c8d 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs @@ -166,6 +166,12 @@ namespace BizHawk.Client.Common protected virtual void Write(string fn, bool backup = false) { + if (Global.Emulator is BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk) + { + var _subnes = (BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk)Global.Emulator; + Header["VBlankCount"] = _subnes.VBL_CNT.ToString(); + } + var file = new FileInfo(fn); if (!file.Directory.Exists) { diff --git a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs index dd5c1e36c4..0cd32aa7ef 100644 --- a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs +++ b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs @@ -4,6 +4,7 @@ using System.Linq; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; using BizHawk.Emulation.Cores.Sega.MasterSystem; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; @@ -336,6 +337,11 @@ namespace BizHawk.Client.Common.MovieConversionExtensions movie.HeaderEntries.Add("Is32X", "1"); } + if (Global.Emulator is SubNESHawk) + { + movie.HeaderEntries.Add("VBlankCount", "0"); + } + movie.Core = ((CoreAttribute)Attribute .GetCustomAttribute(Global.Emulator.GetType(), typeof(CoreAttribute))) .CoreName; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs index 5e31027258..106ebbd9b6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -54,6 +54,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk if (_islag) { _lagcount++; + VBL_CNT++; } return ret; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs index 0f6a4b3e54..201b6d584e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs @@ -54,6 +54,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk ser.Sync("IsLag", ref _islag); ser.Sync("pass_a_frame", ref pass_a_frame); ser.Sync("pass_new_input", ref pass_new_input); + ser.Sync("VBL_CNT", ref VBL_CNT); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index 90b3904778..05c61c4680 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -17,6 +17,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk { public NES.NES subnes; + // needed for movies to accurately calculate timing + public int VBL_CNT; + [CoreConstructor("NES")] public SubNESHawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings) { @@ -41,6 +44,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk SetupMemoryDomains(); HardReset(); + + VBL_CNT = 0; } public void HardReset() From f6dd99a3cecff43ca0ee32a31e8811840c9fdf87 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Jan 2019 14:57:25 -0600 Subject: [PATCH 150/440] GBHawkLink: Fix logic error in linking --- .../Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs | 10 +++++++++- .../Nintendo/GBHawkLink/GBHawkLink.IStatable.cs | 1 + .../Consoles/Nintendo/GBHawkLink/GBHawkLink.cs | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 1cebe9f5b4..dee9cfa0e3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -100,7 +100,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink R.do_single_step(); // the signal to shift out a bit is when serial_clock = 1 - if ((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) + if (((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) && !do_r_next) { if (LinkConnected) { @@ -118,6 +118,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink } else if ((R.serialport.serial_clock == 1) || (R.serialport.serial_clock == 2)) { + do_r_next = false; + if (LinkConnected) { R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); @@ -131,6 +133,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink R.serialport.coming_in = L.serialport.going_out; } + + if (R.serialport.serial_clock == 2) { do_r_next = true; } + } + else + { + do_r_next = false; } // if we hit a frame boundary, update video diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs index 5429566225..7b3049f1e2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -59,6 +59,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink ser.Sync("IsLag", ref _islag); ser.Sync("_cableconnected", ref _cableconnected); ser.Sync("_cablediscosignal", ref _cablediscosignal); + ser.Sync("do_r_next", ref do_r_next); _controllerDeck.SyncState(ser); LinkConnected = _cableconnected; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index d007d533fb..619a17c479 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -30,6 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink // if true, the link cable toggle signal is currently asserted private bool _cablediscosignal = false; + private bool do_r_next = false; + //[CoreConstructor("GB", "GBC")] public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings) { From 90a3053447b743127d8da33d7115061ab73f6abe Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 16:25:56 +1000 Subject: [PATCH 151/440] Update README.md --- README.md | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 558d71de2c..dd2d69d194 100644 --- a/README.md +++ b/README.md @@ -145,9 +145,9 @@ git clone https://github.com/TASVideos/BizHawk.git BizHawk_master ``` ...or use a [Git GUI](https://desktop.github.com). Otherwise, you'll have to download an archive from GitHub. -On Windows 10, open a PowerShell window in BizHawk_master (Shift+Mouse2 in File Explorer) and run `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`. TODO: didn't work for me. On older versions, a similar Command Prompt script should work. +~~On Windows 10, open a PowerShell window in BizHawk_master (Shift+Mouse2 in File Explorer) and run `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`. On older versions, a similar Command Prompt script should work.~~ (Not sure what the right command is. Do let us know.) -The best free C# IDE is [VS Community 2017](https://visualstudio.microsoft.com/vs/community), which you'll need to work on the project efficiently. Open `BizHawk.sln` with VS to start. +For anything more complicated than building, you'll need an IDE like [VS Community 2017](https://visualstudio.microsoft.com/vs/community), currently the best free C# IDE. Open `BizHawk.sln` with VS to start and use the toolbar to choose EmuHawk and build. See [Compiling at TASVideos](http://tasvideos.org/Bizhawk/Compiling.html) (somewhat outdated) for more detailed instructions. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) @@ -176,23 +176,35 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn ## Usage +#### Loading firmware + +You may have seen a dialog saying "You are missing the needed firmware files [...]" when trying to open a rom. Pressing "Yes" opens the Firmware Manager, or you can go to `Config` > `Firmwares...`. + +To load firmware, TODO + +#### Identifying a good rom + +TODO + +#### Rebinding keys and controllers + +TODO + +#### Changing cores + +TODO + +#### Running Lua scripts + TODO [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) ### TASing -This section refers to BizHawk specifically. For resources on TASing in general, see [Welcome to TASVideos](http://tasvideos.org/WelcomeToTASVideos.html). +~~This section refers to BizHawk specifically. For resources on TASing in general, see [Welcome to TASVideos](http://tasvideos.org/WelcomeToTASVideos.html).~~ This section hasn't been written yet. -TODO - -[Commandline](http://tasvideos.org/Bizhawk/CommandLine.html) - -[CompactDiscInfoDump](http://tasvideos.org/Bizhawk/CompactDiscInfoDump.html) - -[Rerecording](http://tasvideos.org/Bizhawk/Rerecording.html) - -[TAS movie file format](http://tasvideos.org/Bizhawk/TASFormat.html) +For now, the best way to learn how to TAS is to browse pages like [BasicTools](http://tasvideos.org/TasingGuide/BasicTools.html) on TASVideos and watch tutorials like [Sand_Knight and dwangoAC's](https://youtu.be/6tJniMaR2Ps). [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) @@ -283,7 +295,7 @@ Past contrbutors to the frontend and custom-built cores are listed [here](https: * [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform -Emulators for other systems can be found on the [EmulatorResources page](http://tasvideos.org/EmulatorResources.html) at TASVideos. The [TASVideos GitHub page](https://github.com/TASVideos) also houses other emulators and plugins where development happens sometimes, their upstreams may be of use. +Emulators for other systems can be found on the [EmulatorResources page](http://tasvideos.org/EmulatorResources.html) at TASVideos. The [TASVideos GitHub page](https://github.com/TASVideos) also holds copies of other emulators and plugins where development happens sometimes, their upstreams may be of use. ## License From 3aa70ba0cf4b49a42f0aac2883020f0229c76274 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 17:22:02 +1000 Subject: [PATCH 152/440] Update README.md --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dd2d69d194..ee2a30dc77 100644 --- a/README.md +++ b/README.md @@ -180,11 +180,14 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn You may have seen a dialog saying "You are missing the needed firmware files [...]" when trying to open a rom. Pressing "Yes" opens the Firmware Manager, or you can go to `Config` > `Firmwares...`. -To load firmware, TODO +To load firmwares, the easiest way is to click "Import" in the menubar, navigate to the dumped firmware(s), select them all, and click "Open". It's a good idea to have them copied into the `Firmware` folder, which is nicely organised, when prompted. If you were trying to open a rom, click "Close and reload ROM" to do that. Keep in mind some firmware is optional and some have multiple versions, only one of which needs to be set. #### Identifying a good rom -TODO +With a core and game loaded, look in the very left of the status bar (`View` > `Display Status Bar`): +* a green checkmark means you've loaded a "known good" rom; +* a "???" (don't remember) means you've loaded a "known bad" rom, created by incorrect dumping methods; and +* a ?-block means you've loaded something unknown, possibly a romhack or homebrew title. #### Rebinding keys and controllers @@ -192,11 +195,17 @@ TODO #### Changing cores -TODO +To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy*, and `N64 Video Plugin Settings`, which you shouldn't touch. #### Running Lua scripts -TODO +(Again, this feature is Windows-only for now.) + +Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded script list and the console output. The buttons below the menubar are shortcuts for items in the menus, hover over them to see what they do. Any script you load is added to the list, and will start running immediately. + +Running scripts have a "⏵" beside their name, and stopped scripts (manually or due to an error) have a "⏹" beside them. Using "Pause or Resume", you can temporarily pause scripts, those have a "⏸". + +"Toggle script" does just that (paused scripts are stopped). "Remove script" stops it and removes it from the list. "Reload script" stops it and loads changes to the file, running scripts are then started again. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From fdc0f26ca608a65d77eefda41d7da012b8a5fcd2 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 17:23:56 +1000 Subject: [PATCH 153/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee2a30dc77..902123e9f6 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores` Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded script list and the console output. The buttons below the menubar are shortcuts for items in the menus, hover over them to see what they do. Any script you load is added to the list, and will start running immediately. -Running scripts have a "⏵" beside their name, and stopped scripts (manually or due to an error) have a "⏹" beside them. Using "Pause or Resume", you can temporarily pause scripts, those have a "⏸". +Running scripts have a "▶️" beside their name, and stopped scripts (manually or due to an error) have a "⏹️" beside them. Using "Pause or Resume", you can temporarily pause scripts, those have a "⏸️". "Toggle script" does just that (paused scripts are stopped). "Remove script" stops it and removes it from the list. "Reload script" stops it and loads changes to the file, running scripts are then started again. From 3e780919045326f3eb800e2f493267413c98837b Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 17:24:36 +1000 Subject: [PATCH 154/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 902123e9f6..761554e010 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded scrip Running scripts have a "▶️" beside their name, and stopped scripts (manually or due to an error) have a "⏹️" beside them. Using "Pause or Resume", you can temporarily pause scripts, those have a "⏸️". -"Toggle script" does just that (paused scripts are stopped). "Remove script" stops it and removes it from the list. "Reload script" stops it and loads changes to the file, running scripts are then started again. +"Toggle script" does just that (paused scripts are stopped). "Reload script" stops it and loads changes to the file, running scripts are then started again. "Remove script" stops it and removes it from the list. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From b6a0afaa1ef7a798e2c63b9ddd3e03f65e6f7ec1 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 23:41:09 +1000 Subject: [PATCH 155/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 761554e010..3dc3bccec5 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ git clone https://github.com/TASVideos/BizHawk.git BizHawk_master ``` ...or use a [Git GUI](https://desktop.github.com). Otherwise, you'll have to download an archive from GitHub. -~~On Windows 10, open a PowerShell window in BizHawk_master (Shift+Mouse2 in File Explorer) and run `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /p:Configuration=Release BizHawk.sln`. On older versions, a similar Command Prompt script should work.~~ (Not sure what the right command is. Do let us know.) +Once it's downloaded and extracted, go into the repo's `Dist` folder and run `BuildAndPackage_Release.bat`. BizHawk will be build into the repo's `output` folder. For anything more complicated than building, you'll need an IDE like [VS Community 2017](https://visualstudio.microsoft.com/vs/community), currently the best free C# IDE. Open `BizHawk.sln` with VS to start and use the toolbar to choose EmuHawk and build. See [Compiling at TASVideos](http://tasvideos.org/Bizhawk/Compiling.html) (somewhat outdated) for more detailed instructions. From c1b85d0cb6a4a31b94e08ef560d9ff33feceed16 Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Jan 2019 23:43:32 +1000 Subject: [PATCH 156/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3dc3bccec5..88a9faee29 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ For now, the best way to learn how to TAS is to browse pages like [BasicTools](h Testing bugfixes or new features can be just as helpful as making them! If code's more your thing, see [*Contributing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) below. -Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build and clicking the check takes you straight there. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. +Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build. Clicking a checkmark and then "Details" in the box that appears takes you straight to the build page. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. From 2448cf38bd715567615a85b0411963e6a63a3edd Mon Sep 17 00:00:00 2001 From: James Groom Date: Mon, 14 Jan 2019 00:10:54 +1000 Subject: [PATCH 157/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88a9faee29..862fec4eb7 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores` (Again, this feature is Windows-only for now.) -Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded script list and the console output. The buttons below the menubar are shortcuts for items in the menus, hover over them to see what they do. Any script you load is added to the list, and will start running immediately. +Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded script list and the console output. The buttons below the menubar are shortcuts for items in the menus, hover over them to see what they do. Any script you load is added to the list, and will start running immediately. Instead of using "Open script", you can drag-and-drop .lua files onto the console or game windows. Running scripts have a "▶️" beside their name, and stopped scripts (manually or due to an error) have a "⏹️" beside them. Using "Pause or Resume", you can temporarily pause scripts, those have a "⏸️". From fefce3d9f1d4a3cc0ed6f00f15903bf028bd2b04 Mon Sep 17 00:00:00 2001 From: James Groom Date: Mon, 14 Jan 2019 00:19:37 +1000 Subject: [PATCH 158/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 862fec4eb7..a5e73a2e58 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ git clone https://github.com/TASVideos/BizHawk.git BizHawk_master ``` ...or use a [Git GUI](https://desktop.github.com). Otherwise, you'll have to download an archive from GitHub. -Once it's downloaded and extracted, go into the repo's `Dist` folder and run `BuildAndPackage_Release.bat`. BizHawk will be build into the repo's `output` folder. +Once it's downloaded and extracted, go into the repo's `Dist` folder and run `BuildAndPackage_Release.bat`. BizHawk will be built as a .zip just like any other release. For anything more complicated than building, you'll need an IDE like [VS Community 2017](https://visualstudio.microsoft.com/vs/community), currently the best free C# IDE. Open `BizHawk.sln` with VS to start and use the toolbar to choose EmuHawk and build. See [Compiling at TASVideos](http://tasvideos.org/Bizhawk/Compiling.html) (somewhat outdated) for more detailed instructions. From 84d163d1cb6eb0a180c60b5d89a4d388f5b7ab32 Mon Sep 17 00:00:00 2001 From: James Groom Date: Mon, 14 Jan 2019 00:29:25 +1000 Subject: [PATCH 159/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5e73a2e58..2c8ec241d0 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ TODO #### Changing cores -To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy*, and `N64 Video Plugin Settings`, which you shouldn't touch. +To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy*, and `N64 Video Plugin Settings`, which you shouldn't touch unless you know what you're doing. #### Running Lua scripts From c6a07396bd0f4e4bdf9b0d471acde67d9851dbbe Mon Sep 17 00:00:00 2001 From: James Groom Date: Mon, 14 Jan 2019 01:37:25 +1000 Subject: [PATCH 160/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c8ec241d0..b6199d943b 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ TODO #### Changing cores -To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy*, and `N64 Video Plugin Settings`, which you shouldn't touch unless you know what you're doing. +To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy* on an SNES. #### Running Lua scripts From 1ae9de0921c00f70542a88c61a8b9326bd4f5618 Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 15 Jan 2019 01:34:36 +1000 Subject: [PATCH 161/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6199d943b..a4ebc4810c 100644 --- a/README.md +++ b/README.md @@ -186,8 +186,8 @@ To load firmwares, the easiest way is to click "Import" in the menubar, navigate With a core and game loaded, look in the very left of the status bar (`View` > `Display Status Bar`): * a green checkmark means you've loaded a "known good" rom; -* a "???" (don't remember) means you've loaded a "known bad" rom, created by incorrect dumping methods; and -* a ?-block means you've loaded something unknown, possibly a romhack or homebrew title. +* a "!" in a red circle means you've loaded a "known bad" rom, created by incorrect dumping methods; and +* something else, usually a ?-block, means you've loaded something unknown, a romhack, or a homebrew title. #### Rebinding keys and controllers From d144479548871ea8ff7e2eb6cb4ff575d9b62a67 Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 15 Jan 2019 01:52:29 +1000 Subject: [PATCH 162/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4ebc4810c..e0a0e4d3ca 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ To load firmwares, the easiest way is to click "Import" in the menubar, navigate With a core and game loaded, look in the very left of the status bar (`View` > `Display Status Bar`): * a green checkmark means you've loaded a "known good" rom; * a "!" in a red circle means you've loaded a "known bad" rom, created by incorrect dumping methods; and -* something else, usually a ?-block, means you've loaded something unknown, a romhack, or a homebrew title. +* something else, usually a ?-block, means you've loaded something that's not in the database. #### Rebinding keys and controllers From 77d099de53a7da39d8efb76fdc6d10f487d8a2db Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 15 Jan 2019 16:00:18 +1000 Subject: [PATCH 163/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0a0e4d3ca..3ee6bec0fc 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores` #### Running Lua scripts -(Again, this feature is Windows-only for now.) +(Reminder that this feature is Windows-only for now.) Go to `Tools` > `Lua Console`. The opened window has two parts, the loaded script list and the console output. The buttons below the menubar are shortcuts for items in the menus, hover over them to see what they do. Any script you load is added to the list, and will start running immediately. Instead of using "Open script", you can drag-and-drop .lua files onto the console or game windows. From 7b71703223997086dc2fc255a6a2d8a69056248d Mon Sep 17 00:00:00 2001 From: James Groom Date: Tue, 15 Jan 2019 18:39:37 +1000 Subject: [PATCH 164/440] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ee6bec0fc..5ab4123902 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,11 @@ Is your distro not there? Released binaries can be found right here on GitHub (s If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -Linux distros are supported if the distributor is still supporting your version, you're using Linux 4.4/4.9/4.14/4.19 LTS or 4.20 for x86_64/amd64, and there are no updates available in your package manager. *Please* update and reboot. +Fixed release distro support: Debian from 8.0 "Jessie", Linux Mint from 19.1 "Tessa", Manjaro from 18.0.2 "Illyria", and Ubuntu (Kubuntu, etc.) from 18.04.1 LTS "Bionic". + +Rolling release distro support (please update and reboot before bothering anyone): Arch Linux from 2018.01.01. + +In general, Linux distros are supported if you're using Linux 4.9/4.14/4.19 LTS or Linux 4.20 on the x86_64/amd64 architecture, *unless* your distributor has ended support. Again, please check there are no updates available in your package manager. macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. From 3f8518e6f292ee33dc8e39440f428858b02d241b Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 00:36:10 +1000 Subject: [PATCH 165/440] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ab4123902..d2f411751a 100644 --- a/README.md +++ b/README.md @@ -195,12 +195,16 @@ With a core and game loaded, look in the very left of the status bar (`View` > ` #### Rebinding keys and controllers -TODO +There are two keybind windows, `Config` > `Controllers...` and `Config` > `Hotkeys...`. These let you bind your keyboard and controllers to virtual controllers and to frontend functions, respectively. + +Using them is simple, click in a box next to an action and press the button (or bump the axis) you want bound to that action. If the "Auto Tab" checkbox at the bottom of the window is checked, the next box will be selected automatically and whatever button you press will be bound to *that* action, and so on down the list. If "Auto Tab" is unchecked, clicking a filled box will let you bind another button to the same action. Keep in mind there are multiple tabs of actions. #### Changing cores To change which core is used for NES, SNES, GB, or GBA, go to `Config` > `Cores`. There, you'll also find the `GB in SGB` item, which is a checkbox that makes GB games run with the *Super Game Boy* on an SNES. +Most cores have their own settings window too, look in the menubar for the system name after `Tools`. Some have multiple windows, like Mupen64Plus which has virtual controller settings and graphics settings. + #### Running Lua scripts (Reminder that this feature is Windows-only for now.) From 3aec48de7f63a9752ea230f2a315314eaf8ab181 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 00:43:53 +1000 Subject: [PATCH 166/440] Update README.md --- README.md | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index d2f411751a..1bb1e445a9 100644 --- a/README.md +++ b/README.md @@ -111,30 +111,13 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag ### GNU+Linux and macOS -Install BizHawk with your distro's package manager. The package name is given on each button below, and some buttons are links. For the changelog, [see TASVideos here](http://tasvideos.org/Bizhawk/ReleaseHistory.html). +**IMPORTANT**: The Mono "port" is a work-in-progress! It is *not* complete, does *not* look very nice and is *not* ready for anything that needs accuracy. -[![Arch Linux (AUR) | bizhawk](https://img.shields.io/badge/Arch_Linux_(AUR)-bizhawk-%231793D1.svg?logo=arch-linux&style=popout)](https://aur.archlinux.org/packages/bizhawk) -[![Debian (Launchpad) | bizhawk](https://img.shields.io/badge/Debian_(Launchpad)-bizhawk-%23A81D33.svg?logo=debian&style=popout)](https://example.com/bizhawk) -[![Linux Mint (Launchpad) | bizhawk](https://img.shields.io/badge/Linux_Mint_(Launchpad)-bizhawk-%2387CF3E.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAF7UlEQVR4nO2bXWwUVRTHz1YEsRaNRDEqpkbUYE2RENhuZ85F/AqJIWKIxvigJqgEtSpYisWIl92dc31Qo6BiTHww0UiIMQQjpERs1NJuuzvnEkMUEpSYKBI/AI0YoGXxoR/p3pltu7vTsi3zT87bmTn3/PbeM/drAUKFCnVeizQeIMbD5W6K8VelxSHFuJcYdxLjJmKxPN5l1chWmFQ0AMXiuNLi7Pg1zBLjQWJ8Pc72HACInGcABhmLHmKxK8lCjBjEhAKQAwK3yFT02oIBOK54x9H4eDkaMa4kjescxs2K8WvS4thQIEiLI0nXXlIQgKRr3z+irlMGamyprXQy1iJi+z2l8agvBBbdjotrIN+QGM8ABos6F0wnxvX+Qxqzjisk+EGYKAD6JTvqqolxp3c44Bnl4jOeB4ICQJ32TZTBpQPGuLDkbIrUk5l5FzqMRBrPGCBOkmthjnNgADSuM4inAsmmeEWIxYtKY9Zo14GmNqtqwGsCAwAAiJC23/YWRtww4DHBAcCq9thUpQUb84TjTio6AwB85gHaflimotNkKjqtsaW2Um6tmQwjmFWVKwAAAHItVCx6ciC49ksA4AVALLpJ46l+UxqPksYUufi8bK2+KG+QMgYAvfXgC7MWyFaYVNBUmDR+nm/lVQqAhh2zpiTS9u1KYzMxblKueJNcsUKydbXpm+gU1zuMDcS4sdfs1UrXz39gK1wwVAwng/eac4N4Oja34LVAknFZUACkhArS4lHS+JNZrfsa+Y/S2CxbYVJjS20lsXhLaXHSb6JDjK7KiHvyxVrVHptKjL/n9nZ7deGLIRYfBgFASqggxk3+iXuq9hal8dvh/US3w/YL+WIqxm3Gez8BYlzoMN6Zz4hxowGgIwgAjouPjST5Qo1YdDvautsXgLZfMQC4Q7Wxr6HiaaO77SsVgJRQoTTu8+ldx4nxS8W4mxj/zp8oHiUWu5TGVqXFv9734G7w+XI5bD9ixPutcAAsvi8VADFeoRhPG43em2yPXdPvk+wSM/0gEYt2uaf+yn6/RKb+BmI8aNaOhh2zpphxk669xOgBJ84JANlRV21+lymDS72xrQdNAAlX3OGJ7eITRuxTMhWdZvop115s+pUJAMwS4y2mX5ztOUbsnmSXmOkFYKGZ2NrMvEvHFYBE2rrZEztdf6tZ4AYPk34ltagPAYQAQgAhgBBACCAEEAIIAYQAQgDBAlDafspoxA/gs9YuBEBTm1VFjCt7391rsvW2yzyg2mOXD/YhxpWNLbWVYwrAXGoqLQ6VCiBojfIQyF2Tk8a//DYbTACKcW9A+Q2rUQWQZCGMGtDjt12t2F5rDJU/hzpHCFKjCkBm7OvMU1a/TUfvUMFsMmPbAeU4pPwABLYjJLfWTCYtjuT+uoMOF/M0om8YbJMSKgLKM68U23cZcf9b1R6b6vErBgAAgHnhgFh0gVEI+w4eDpu9QGlsHu7UplQpjc0GgJ/9YhYPwMUmsw4k3LrZHj/GDZ5eoDGrGPcoxpcdbT9HbD8blDkuriGN7xPjCQPAp76gigUQ77JqvLct8A3Tr6nNqvLd7x9Tw2xS432BApASKhRjJvdhcUx2zb/K9E3o6I3effoxNBbb8w25ogEAAJArVpjBiPFdP18nFZ1BGj8iFt1jlThpPNN3OdJT/QMBIFtrLiEtfjHG2mknYy3K80gk4dbNJsb1xLhTsfhOadwfsO0jLb5SLF5LulYdDHORoyQAAH7nhL0V12+B4gdklGzEKhlAw45ZU4hF2jsURJo6F0wv6GXnQCUDAACIp2Nzlc+JLDG6sqOuOvhmB6dAAAAAEIvlPpcQz5IWRxzGh8Zi9leMAgMAAJHeywa+11qyxOIbyuBSmZl3cZAJlKogAQAARJTGZs/1s9xv8h+KxXbF4lVie7XD2HCObXOQAAAAIMm4zLx8NF4sEAAAvbc5iMXHYznxKSsAfYrE07G5isUH+f68UG4WNIABNbVZVcq1FzuMcaXFZ8Siq2/m9mOZ2f5RARAqVKhxo/8B55jpMzoUPycAAAAASUVORK5CYII=&style=popout)](https://example.com/bizhawk) -[![macOS (Homebrew) | bizhawk](https://img.shields.io/badge/macOS_(Homebrew)-bizhawk-%23999999.svg?logo=apple&style=popout)](https://example.com/bizhawk) -[![Manjaro (AUR) | bizhawk](https://img.shields.io/badge/Manjaro_(AUR)-bizhawk-%2335BF5C.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABRUlEQVR4nO3bQUrDQBTG8Qdu3dS91r2CAzYE3Cm9QBURmjq7Yk9QIsELJYJ2XYqh7UJbL9NcYFyoGAQZiFMygf8Hb/vNm192IREhhJBS+ou4Fa3vM71Kitv3B1P3lHer2qFXSTFYJ2l/EbesANev46y7HJkw1yZ4GdQ+5d2qdoS5Nt3lyNy8xakV4Hw+LOq+tGuA77mY322sAL48+W0AhLk2f93b2SE+A/zuAwAAAAAAAAAAAAAAAAAAcH3IqcNpJMBWAkATAVy+E2wkgE9dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAZzrTaOPT0i67OtPI/suMyq6efVraZdfJ4+WTFWD3bP9Ypb1JMIsq/zzlHcAsKlTam+wFB0dWABHZEZFDEVHi4NO2f3S47FIi0v66GyHkJx/0rGTAdYdsEwAAAABJRU5ErkJggg==&style=popout)](https://aur.archlinux.org/packages/bizhawk) -[![Ubuntu (Launchpad) | bizhawk](https://img.shields.io/badge/Ubuntu_(Launchpad)-bizhawk-%23E95420.svg?colorA=772953&logo=ubuntu&style=popout)](https://example.com/bizhawk) +You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). -If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See #1430 for progress. +Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -Is your distro not there? Released binaries can be found right here on GitHub (same download as for Windows): - -[![Misc. Linux | binaries](https://img.shields.io/badge/Misc._Linux-binaries-%23FCC624.svg?logo=linux&logoColor=black&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) - -If you download BizHawk this way, **don't mix different versions**, keep each version in its own folder. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). - -Fixed release distro support: Debian from 8.0 "Jessie", Linux Mint from 19.1 "Tessa", Manjaro from 18.0.2 "Illyria", and Ubuntu (Kubuntu, etc.) from 18.04.1 LTS "Bionic". - -Rolling release distro support (please update and reboot before bothering anyone): Arch Linux from 2018.01.01. - -In general, Linux distros are supported if you're using Linux 4.9/4.14/4.19 LTS or Linux 4.20 on the x86_64/amd64 architecture, *unless* your distributor has ended support. Again, please check there are no updates available in your package manager. - -macOS is supported from 10.11 "El Capitan" (Darwin 15.6). Apple doesn't seem to care about lifecycles, so we'll go with 6 months from the last security update. +If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Sega Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See #1430 for progress. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From b7fd548b73d5482d0a7de7d259e7addb26438e65 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 00:44:47 +1000 Subject: [PATCH 167/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1bb1e445a9..697bc9c7e3 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag ### GNU+Linux and macOS -**IMPORTANT**: The Mono "port" is a work-in-progress! It is *not* complete, does *not* look very nice and is *not* ready for anything that needs accuracy. +**IMPORTANT**: The Mono "port" is a work-in-progress! It is *not* complete, does *not* look very nice, and is *not* ready for anything that needs accuracy. You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). From ba58fa356201812bf06fd08e7ba5233b37de1220 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 00:54:42 +1000 Subject: [PATCH 168/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 697bc9c7e3..40d2a78d92 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Supported consoles and computers: * Saturn * SG-1000 * Sinclair ZX Spectrum -* Sony Playstation / PSX +* Sony Playstation (PSX) * Texas Instruments TI-83 * Uzebox * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? From d54b3778192b46f4bfcc271d558e9a9402b1fb8c Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:08:39 +1000 Subject: [PATCH 169/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40d2a78d92..89b65bf622 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Before you start (by running `EmuHawk.exe`), you'll need the following Windows-o BizHawk functions like a "portable" program, you may move or rename the folder containing `EmuHawk.exe`, even to another drive — as long as you keep all the files together, and the prerequisites are installed when you go to run it. -Win7 is supported from SP1, Win8 is supported from 8.1, and Win10 is supported from 1709 "Redstone 3", following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). +Following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet), Win10 is supported from 1709 "Redstone 3", Win8 is supported from 8.1, and Win7 is supported from SP1 (ends Jan 2020, upgrade to Win10 or try [ReactOS](https://reactos.org/joining/faqs)). A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for Windows XP and 32-bit users. Being in the 1.x series, many bugs remain and features are missing. From 81ba01371105ab65e0d80a627cab97fae919396f Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:09:24 +1000 Subject: [PATCH 170/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 89b65bf622..8e73d7a960 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ Supported consoles and computers: See [*Usage*](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) below for details about specific tools and config menus. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Installing ### Windows 7/8.1/10 From 1ac45bbdb82c529d1ac2b0caafb4dd0a8b365528 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:09:54 +1000 Subject: [PATCH 171/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8e73d7a960..aefa5f6294 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,8 @@ For the time being, style is not enforced in PRs, only build success is. Please Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. +[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) + ## Related projects * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform From 8c7375147b8ebdf3fd248d76ab870f7973046125 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:10:36 +1000 Subject: [PATCH 172/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aefa5f6294..45c815bc8f 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,7 @@ If you'd like to add a feature, first search the issue tracker for it. If it's a For the time being, style is not enforced in PRs, only build success is. Please use CRLF, tabs, and [Allman braces](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) in new files. -Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See a core's docs for its authors. +Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See the wiki for core authors. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From 08d9c0a724e57ae30cf18dd747096b189202446a Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:13:20 +1000 Subject: [PATCH 173/440] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 45c815bc8f..900f1ccadc 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ New user on Windows? Install the prerequisites first, click the "prereqs" button Jump to: * Installing * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) - * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) + * [GNU+Linux](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux) * Building * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) - * [GNU+Linux and macOS](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) + * [GNU+Linux](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) * [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) @@ -111,11 +111,11 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) -### GNU+Linux and macOS +### GNU+Linux **IMPORTANT**: The Mono "port" is a work-in-progress! It is *not* complete, does *not* look very nice, and is *not* ready for anything that needs accuracy. -You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). +You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). @@ -140,7 +140,7 @@ For anything more complicated than building, you'll need an IDE like [VS Communi [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) -### GNU+Linux and macOS +### GNU+Linux *Compiling* requires MSBuild and *running* requires Mono and WINE, but **BizHawk does not run under WINE** — only the bundled libraries are required. @@ -157,7 +157,7 @@ Remove the `/p:...` flag from MSBuild if you want debugging symbols. If your distro isn't listed under *Installing* above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -Once built, see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-and-macos) above, substituting the repo's `output` folder for the download. +Once built, see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux) above, substituting the repo's `output` folder for the download. Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). From 934e7edde225f86b19f134a1aa6b7e6d5f529ba4 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:18:41 +1000 Subject: [PATCH 174/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 900f1ccadc..7c9c1a30a1 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ You'll need to either build BizHawk yourself (see [*Building*](https://github.co Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Sega Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See #1430 for progress. +If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Sega Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From 01265a2893388beadd69a7d1c957b961bf5ff3ed Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:26:11 +1000 Subject: [PATCH 175/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7c9c1a30a1..af97a7cac2 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). +The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` if available), `libdl.so` (glibc), NVIDIA's `cgc` utility. LSB release info is optional for automatically setting the library location. + Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Sega Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. From a94a970b01b217648b1cf19684c7c5ee224ab4ae Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 01:33:55 +1000 Subject: [PATCH 176/440] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index af97a7cac2..ddd1457b35 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,8 @@ You may have seen a dialog saying "You are missing the needed firmware files [.. To load firmwares, the easiest way is to click "Import" in the menubar, navigate to the dumped firmware(s), select them all, and click "Open". It's a good idea to have them copied into the `Firmware` folder, which is nicely organised, when prompted. If you were trying to open a rom, click "Close and reload ROM" to do that. Keep in mind some firmware is optional and some have multiple versions, only one of which needs to be set. +Windows users can keep the `Firmware` folder made by the firmware manager when updating, go to `Config` > `Paths...` and change "Firmware" under "Global" to point at it. + #### Identifying a good rom With a core and game loaded, look in the very left of the status bar (`View` > `Display Status Bar`): From 08c050648322d8371ad198808263c29d585c5b50 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 16 Jan 2019 03:48:09 +1000 Subject: [PATCH 177/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ddd1457b35..d89236f51c 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). -The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` if available), `libdl.so` (glibc), NVIDIA's `cgc` utility. LSB release info is optional for automatically setting the library location. +The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` if available), `libdl.so` (glibc), NVIDIA's `cgc` utility, and `libblip_buf.so` from the repo's `Assets` folder (copy it to `/usr/lib/libblip_buf.so.1.1.0` or equivalent). LSB release info is optional for automatically setting the library location. Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). From 65ce3abaa94ef585c9a87e7064b9f8ef296ae2e9 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 17 Jan 2019 16:42:27 -0500 Subject: [PATCH 178/440] NES Mapper034.cs is missing SyncState (#1451) * NES Mapper034.cs is missing SyncState --- .../Consoles/Nintendo/NES/Boards/Mapper034.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper034.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper034.cs index 34436b66cd..472f229a4d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper034.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper034.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; +using BizHawk.Common; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -13,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int prg_bank_mask_32k, chr_bank_mask_4k; //state - int[] chr = new int[2]; + ByteBuffer chr = new ByteBuffer(2); int prg; @@ -38,6 +39,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES return true; } + public override void Dispose() + { + chr.Dispose(); + base.Dispose(); + } + public override byte ReadPPU(int addr) { if (addr < 0x2000) @@ -64,10 +71,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES prg = value & prg_bank_mask_32k; break; case 0x1ffe: - chr[0] = value & chr_bank_mask_4k; + chr[0] = (byte)(value & chr_bank_mask_4k); break; case 0x1fff: - chr[1] = value & chr_bank_mask_4k; + chr[1] = (byte)(value & chr_bank_mask_4k); break; default: // on NINA, the regs sit on top of WRAM @@ -75,5 +82,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES break; } } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("prg", ref prg); + ser.Sync("chr", ref chr); + } } } From ca9385c3c8b4befe632dcb4c67271827fb31a14c Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 18 Jan 2019 00:59:23 -0500 Subject: [PATCH 179/440] add some little fragments i meant for the user display cropping stuff but didnt use --- .../GdiPlusGuiRenderer.cs | 19 ++++++++++++++++++- Bizware/BizHawk.Bizware.BizwareGL/Art.cs | 10 ++++++++++ .../BizHawk.Bizware.BizwareGL/GuiRenderer.cs | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/GdiPlusGuiRenderer.cs b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/GdiPlusGuiRenderer.cs index 06ed24b922..c1ee8d0644 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/GdiPlusGuiRenderer.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/GdiPlusGuiRenderer.cs @@ -240,7 +240,17 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.GdiPlus g.Transform = new sd.Drawing2D.Matrix(mat.M11, mat.M12, mat.M21, mat.M22, mat.M41, mat.M42); } + unsafe void DrawInternal(Art art, float x, float y, float w, float h) + { + DrawInternal(art.BaseTexture, x, y, w, h, art.u0, art.v0, art.u1, art.v1); + } + unsafe void DrawInternal(Texture2d tex, float x, float y, float w, float h) + { + DrawInternal(tex, x, y, w, h, 0, 0, 1, 1); + } + + unsafe void DrawInternal(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1) { var g = Gdi.GetCurrentGraphics(); PrepDraw(g, tex); @@ -253,9 +263,16 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.GdiPlus new sd.PointF(x,y+h), }; + float sx = tex.Width * u0; + float sy = tex.Height * v0; + float sx2 = tex.Width * u1; + float sy2 = tex.Height * v1; + float sw = sx2 - sx; + float sh = sy2 - sy; + var tw = tex.Opaque as IGL_GdiPlus.TextureWrapper; g.PixelOffsetMode = sd.Drawing2D.PixelOffsetMode.Half; - g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(0, 0, tex.Width, tex.Height), sd.GraphicsUnit.Pixel, CurrentImageAttributes); + g.DrawImage(tw.SDBitmap, destPoints, new sd.RectangleF(sx, sy, sw, sh), sd.GraphicsUnit.Pixel, CurrentImageAttributes); g.Transform = new sd.Drawing2D.Matrix(); //.Reset() doesnt work ? ? } diff --git a/Bizware/BizHawk.Bizware.BizwareGL/Art.cs b/Bizware/BizHawk.Bizware.BizwareGL/Art.cs index 5992872e23..13db7e68a6 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/Art.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL/Art.cs @@ -5,6 +5,16 @@ namespace BizHawk.Bizware.BizwareGL /// public class Art { + //bleh, didnt mean to have this here, but I need it now + public Art(Texture2d tex) + { + BaseTexture = tex; + u1 = 1; + v1 = 1; + Width = tex.Width; + Height = tex.Height; + } + internal Art(ArtManager owner) { Owner = owner; diff --git a/Bizware/BizHawk.Bizware.BizwareGL/GuiRenderer.cs b/Bizware/BizHawk.Bizware.BizwareGL/GuiRenderer.cs index 9ecf4b5e5d..d4b25aac90 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/GuiRenderer.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL/GuiRenderer.cs @@ -224,7 +224,7 @@ namespace BizHawk.Bizware.BizwareGL unsafe void DrawInternal(Texture2d tex, float x, float y, float w, float h) { - Art art = new Art(null); + Art art = new Art((ArtManager)null); art.Width = w; art.Height = h; art.u0 = art.v0 = 0; From cecdff8293a14d2f8f312b2b08be224a4aba2387 Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 18 Jan 2019 00:59:38 -0500 Subject: [PATCH 180/440] config hookup for user crop area --- BizHawk.Client.Common/config/Config.cs | 6 + .../config/DisplayConfigLite.Designer.cs | 190 ++++++++++++++---- .../config/DisplayConfigLite.cs | 10 + .../config/DisplayConfigLite.resx | 3 + 4 files changed, 167 insertions(+), 42 deletions(-) diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index b7f72ab639..1ced4b01f1 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -363,6 +363,12 @@ namespace BizHawk.Client.Common public float DispCustomUserARX = -1; public float DispCustomUserARY = -1; + //these default to 0 because by default we crop nothing + public int DispCropLeft = 0; + public int DispCropTop = 0; + public int DispCropRight = 0; + public int DispCropBottom = 0; + // Sound options #if WINDOWS public ESoundOutputMethod SoundOutputMethod = ESoundOutputMethod.DirectSound; diff --git a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs index 4e22222325..8d6155f93d 100644 --- a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs @@ -37,6 +37,7 @@ this.lblUserFilterName = new System.Windows.Forms.Label(); this.btnSelectUserFilter = new System.Windows.Forms.Button(); this.rbUser = new System.Windows.Forms.RadioButton(); + this.tbScanlineIntensity = new BizHawk.Client.EmuHawk.TransparentTrackBar(); this.rbNone = new System.Windows.Forms.RadioButton(); this.rbScanlines = new System.Windows.Forms.RadioButton(); this.rbHq2x = new System.Windows.Forms.RadioButton(); @@ -64,6 +65,16 @@ this.label5 = new System.Windows.Forms.Label(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tpAR = new System.Windows.Forms.TabPage(); + this.groupBox6 = new System.Windows.Forms.GroupBox(); + this.label16 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.txtCropBottom = new System.Windows.Forms.TextBox(); + this.label17 = new System.Windows.Forms.Label(); + this.txtCropRight = new System.Windows.Forms.TextBox(); + this.txtCropTop = new System.Windows.Forms.TextBox(); + this.label14 = new System.Windows.Forms.Label(); + this.txtCropLeft = new System.Windows.Forms.TextBox(); + this.btnDefaults = new System.Windows.Forms.Button(); this.cbAutoPrescale = new System.Windows.Forms.CheckBox(); this.label11 = new System.Windows.Forms.Label(); this.label10 = new System.Windows.Forms.Label(); @@ -95,17 +106,17 @@ this.cbStatusBarWindowed = new System.Windows.Forms.CheckBox(); this.label9 = new System.Windows.Forms.Label(); this.cbMenuWindowed = new System.Windows.Forms.CheckBox(); + this.trackbarFrameSizeWindowed = new BizHawk.Client.EmuHawk.TransparentTrackBar(); this.cbCaptionWindowed = new System.Windows.Forms.CheckBox(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); - this.tbScanlineIntensity = new BizHawk.Client.EmuHawk.TransparentTrackBar(); - this.trackbarFrameSizeWindowed = new BizHawk.Client.EmuHawk.TransparentTrackBar(); - this.btnDefaults = new System.Windows.Forms.Button(); this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.tbScanlineIntensity)).BeginInit(); this.grpFinalFilter.SuspendLayout(); this.grpARSelection.SuspendLayout(); this.tabControl1.SuspendLayout(); this.tpAR.SuspendLayout(); + this.groupBox6.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudPrescale)).BeginInit(); this.tpDispMethod.SuspendLayout(); this.groupBox3.SuspendLayout(); @@ -114,7 +125,6 @@ this.tabPage1.SuspendLayout(); this.groupBox4.SuspendLayout(); this.groupBox2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tbScanlineIntensity)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackbarFrameSizeWindowed)).BeginInit(); this.SuspendLayout(); // @@ -196,6 +206,19 @@ this.rbUser.Text = "User"; this.rbUser.UseVisualStyleBackColor = true; // + // tbScanlineIntensity + // + this.tbScanlineIntensity.LargeChange = 32; + this.tbScanlineIntensity.Location = new System.Drawing.Point(83, 55); + this.tbScanlineIntensity.Maximum = 256; + this.tbScanlineIntensity.Name = "tbScanlineIntensity"; + this.tbScanlineIntensity.Size = new System.Drawing.Size(70, 42); + this.tbScanlineIntensity.TabIndex = 3; + this.tbScanlineIntensity.TickFrequency = 32; + this.tbScanlineIntensity.TickStyle = System.Windows.Forms.TickStyle.TopLeft; + this.tbScanlineIntensity.Scroll += new System.EventHandler(this.tbScanlineIntensity_Scroll); + this.tbScanlineIntensity.ValueChanged += new System.EventHandler(this.tbScanlineIntensity_Scroll); + // // rbNone // this.rbNone.AutoSize = true; @@ -474,6 +497,7 @@ // // tpAR // + this.tpAR.Controls.Add(this.groupBox6); this.tpAR.Controls.Add(this.btnDefaults); this.tpAR.Controls.Add(this.cbAutoPrescale); this.tpAR.Controls.Add(this.label11); @@ -492,6 +516,102 @@ this.tpAR.Text = "Scaling & Filtering"; this.tpAR.UseVisualStyleBackColor = true; // + // groupBox6 + // + this.groupBox6.Controls.Add(this.label16); + this.groupBox6.Controls.Add(this.label15); + this.groupBox6.Controls.Add(this.txtCropBottom); + this.groupBox6.Controls.Add(this.label17); + this.groupBox6.Controls.Add(this.txtCropRight); + this.groupBox6.Controls.Add(this.txtCropTop); + this.groupBox6.Controls.Add(this.label14); + this.groupBox6.Controls.Add(this.txtCropLeft); + this.groupBox6.Location = new System.Drawing.Point(218, 195); + this.groupBox6.Name = "groupBox6"; + this.groupBox6.Size = new System.Drawing.Size(302, 61); + this.groupBox6.TabIndex = 9; + this.groupBox6.TabStop = false; + this.groupBox6.Text = "Cropping"; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(217, 25); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(43, 13); + this.label16.TabIndex = 30; + this.label16.Text = "Bottom:"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(74, 25); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(29, 13); + this.label15.TabIndex = 29; + this.label15.Text = "Top:"; + // + // txtCropBottom + // + this.txtCropBottom.Location = new System.Drawing.Point(261, 22); + this.txtCropBottom.Name = "txtCropBottom"; + this.txtCropBottom.Size = new System.Drawing.Size(34, 20); + this.txtCropBottom.TabIndex = 28; + this.txtCropBottom.Text = "8000"; + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(144, 25); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(35, 13); + this.label17.TabIndex = 26; + this.label17.Text = "Right:"; + // + // txtCropRight + // + this.txtCropRight.Location = new System.Drawing.Point(180, 22); + this.txtCropRight.Name = "txtCropRight"; + this.txtCropRight.Size = new System.Drawing.Size(34, 20); + this.txtCropRight.TabIndex = 25; + this.txtCropRight.Text = "8000"; + // + // txtCropTop + // + this.txtCropTop.Location = new System.Drawing.Point(104, 22); + this.txtCropTop.Name = "txtCropTop"; + this.txtCropTop.Size = new System.Drawing.Size(34, 20); + this.txtCropTop.TabIndex = 24; + this.txtCropTop.Text = "8000"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(6, 25); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(28, 13); + this.label14.TabIndex = 16; + this.label14.Text = "Left:"; + // + // txtCropLeft + // + this.txtCropLeft.Location = new System.Drawing.Point(34, 22); + this.txtCropLeft.Name = "txtCropLeft"; + this.txtCropLeft.Size = new System.Drawing.Size(34, 20); + this.txtCropLeft.TabIndex = 15; + this.txtCropLeft.Text = "8000"; + // + // btnDefaults + // + this.btnDefaults.Location = new System.Drawing.Point(447, 262); + this.btnDefaults.Name = "btnDefaults"; + this.btnDefaults.Size = new System.Drawing.Size(75, 23); + this.btnDefaults.TabIndex = 18; + this.btnDefaults.Text = "Defaults"; + this.toolTip1.SetToolTip(this.btnDefaults, "Unless I forgot to update the button\'s code when I changed a default"); + this.btnDefaults.UseVisualStyleBackColor = true; + this.btnDefaults.Click += new System.EventHandler(this.btnDefaults_Click); + // // cbAutoPrescale // this.cbAutoPrescale.AutoSize = true; @@ -602,8 +722,7 @@ this.label8.Name = "label8"; this.label8.Size = new System.Drawing.Size(359, 27); this.label8.TabIndex = 20; - this.label8.Text = " • Best compatibility\r\n • May have trouble with OpenGL-based cores (N64)\r\n" + - ""; + this.label8.Text = " • Best compatibility\r\n • May have trouble with OpenGL-based cores (N64)\r\n"; // // rbD3D9 // @@ -835,6 +954,17 @@ this.cbMenuWindowed.Text = "Menu"; this.cbMenuWindowed.UseVisualStyleBackColor = true; // + // trackbarFrameSizeWindowed + // + this.trackbarFrameSizeWindowed.LargeChange = 1; + this.trackbarFrameSizeWindowed.Location = new System.Drawing.Point(6, 33); + this.trackbarFrameSizeWindowed.Maximum = 2; + this.trackbarFrameSizeWindowed.Name = "trackbarFrameSizeWindowed"; + this.trackbarFrameSizeWindowed.Size = new System.Drawing.Size(99, 42); + this.trackbarFrameSizeWindowed.TabIndex = 21; + this.trackbarFrameSizeWindowed.Value = 1; + this.trackbarFrameSizeWindowed.ValueChanged += new System.EventHandler(this.trackbarFrameSizeWindowed_ValueChanged); + // // cbCaptionWindowed // this.cbCaptionWindowed.AutoSize = true; @@ -856,41 +986,6 @@ this.linkLabel1.Text = "Documentation"; this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); // - // tbScanlineIntensity - // - this.tbScanlineIntensity.LargeChange = 32; - this.tbScanlineIntensity.Location = new System.Drawing.Point(83, 55); - this.tbScanlineIntensity.Maximum = 256; - this.tbScanlineIntensity.Name = "tbScanlineIntensity"; - this.tbScanlineIntensity.Size = new System.Drawing.Size(70, 42); - this.tbScanlineIntensity.TabIndex = 3; - this.tbScanlineIntensity.TickFrequency = 32; - this.tbScanlineIntensity.TickStyle = System.Windows.Forms.TickStyle.TopLeft; - this.tbScanlineIntensity.Scroll += new System.EventHandler(this.tbScanlineIntensity_Scroll); - this.tbScanlineIntensity.ValueChanged += new System.EventHandler(this.tbScanlineIntensity_Scroll); - // - // trackbarFrameSizeWindowed - // - this.trackbarFrameSizeWindowed.LargeChange = 1; - this.trackbarFrameSizeWindowed.Location = new System.Drawing.Point(6, 33); - this.trackbarFrameSizeWindowed.Maximum = 2; - this.trackbarFrameSizeWindowed.Name = "trackbarFrameSizeWindowed"; - this.trackbarFrameSizeWindowed.Size = new System.Drawing.Size(99, 42); - this.trackbarFrameSizeWindowed.TabIndex = 21; - this.trackbarFrameSizeWindowed.Value = 1; - this.trackbarFrameSizeWindowed.ValueChanged += new System.EventHandler(this.trackbarFrameSizeWindowed_ValueChanged); - // - // btnDefaults - // - this.btnDefaults.Location = new System.Drawing.Point(447, 262); - this.btnDefaults.Name = "btnDefaults"; - this.btnDefaults.Size = new System.Drawing.Size(75, 23); - this.btnDefaults.TabIndex = 18; - this.btnDefaults.Text = "Defaults"; - this.toolTip1.SetToolTip(this.btnDefaults, "Unless I forgot to update the button\'s code when I changed a default"); - this.btnDefaults.UseVisualStyleBackColor = true; - this.btnDefaults.Click += new System.EventHandler(this.btnDefaults_Click); - // // DisplayConfigLite // this.AcceptButton = this.btnOk; @@ -908,6 +1003,7 @@ this.Text = "Display Configuration"; this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.tbScanlineIntensity)).EndInit(); this.grpFinalFilter.ResumeLayout(false); this.grpFinalFilter.PerformLayout(); this.grpARSelection.ResumeLayout(false); @@ -915,6 +1011,8 @@ this.tabControl1.ResumeLayout(false); this.tpAR.ResumeLayout(false); this.tpAR.PerformLayout(); + this.groupBox6.ResumeLayout(false); + this.groupBox6.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudPrescale)).EndInit(); this.tpDispMethod.ResumeLayout(false); this.groupBox3.ResumeLayout(false); @@ -929,7 +1027,6 @@ this.groupBox4.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tbScanlineIntensity)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackbarFrameSizeWindowed)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -1009,5 +1106,14 @@ private System.Windows.Forms.CheckBox cbFullscreenHacks; private System.Windows.Forms.Button btnDefaults; private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.GroupBox groupBox6; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.TextBox txtCropBottom; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.TextBox txtCropRight; + private System.Windows.Forms.TextBox txtCropTop; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.TextBox txtCropLeft; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.cs b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.cs index 1c5179f74f..a2cd975168 100644 --- a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.cs +++ b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.cs @@ -85,6 +85,11 @@ namespace BizHawk.Client.EmuHawk if (Global.Config.DispCustomUserARY != -1) txtCustomARY.Text = Global.Config.DispCustomUserARY.ToString(); + txtCropLeft.Text = Global.Config.DispCropLeft.ToString(); + txtCropTop.Text = Global.Config.DispCropTop.ToString(); + txtCropRight.Text = Global.Config.DispCropRight.ToString(); + txtCropBottom.Text = Global.Config.DispCropBottom.ToString(); + RefreshAspectRatioOptions(); } @@ -173,6 +178,11 @@ namespace BizHawk.Client.EmuHawk if(rbD3D9.Checked) Global.Config.DispMethod = Config.EDispMethod.SlimDX9; + int.TryParse(txtCropLeft.Text, out Global.Config.DispCropLeft); + int.TryParse(txtCropTop.Text, out Global.Config.DispCropTop); + int.TryParse(txtCropRight.Text, out Global.Config.DispCropRight); + int.TryParse(txtCropBottom.Text, out Global.Config.DispCropBottom); + if (oldDisplayMethod != Global.Config.DispMethod) NeedReset = true; diff --git a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.resx b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.resx index 60237ce856..c5e4444e45 100644 --- a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.resx +++ b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.resx @@ -126,4 +126,7 @@ For Windows operating systems >= Vista, with some video cards, the monitors may flicker when going 'windowed fullscreen' while the system disobeys us and goes actual fullscreen instead. This hack prevents that, but may increase frame latency (since in Microsoft's new and disimproved operating systems, windowed mode things may have higher latency) + + 17, 17 + \ No newline at end of file From 578bb546f3cc4bbbda1f0c26acf06d9f4b3d8800 Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 18 Jan 2019 01:00:07 -0500 Subject: [PATCH 181/440] bad attempt at implementing user crop area. need to do differently. needs to happen.. like... as soon as we get the video provider. --- .../DisplayManager/DisplayManager.cs | 56 +++++++++++++++++-- .../DisplayManager/Filters/Gui.cs | 27 +++++++-- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index fc7ccbc84b..b1fa0804f1 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -222,6 +222,30 @@ namespace BizHawk.Client.EmuHawk //add the first filter, encompassing output from the emulator core chain.AddFilter(fInput, "input"); + Size currSize = chain_insize; + + //apply user's choice of cropping + //NOTE 1. this is going to break the positioning of elements in lua + //we COULD change how this works to apply it at a different point; but let's wait for someone to ask for it + //we can offer "fix the lua script" as a response, as well, to rebuff them + //NOTE 2. this is an inefficient way of doing it. this could be done if we use 'art' everywhere instead of textures. + //then, we could adjust the uv coords and carry on, rather than doing this extra resolving step. + //Well.... not today + int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; + int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; + if (cropX != 0 || cropY != 0) + { + currSize.Width -= cropX; + currSize.Height -= cropY; + + Filters.FinalPresentation fCrop = new Filters.FinalPresentation(currSize); + fCrop.Config_Crop = true; + fCrop.Crop = new Rectangle(Global.Config.DispCropLeft, Global.Config.DispCropTop, cropX, cropY); + fCrop.GuiRenderer = Renderer; + fCrop.GL = GL; + chain.AddFilter(fCrop, "crop"); + } + //if a non-zero padding is required, add a filter to allow for that //note, we have two sources of padding right now.. one can come from the videoprovider and one from the user. //we're combining these now and just using black, for sake of being lean, despite the discussion below: @@ -231,7 +255,7 @@ namespace BizHawk.Client.EmuHawk if (padding.Vertical != 0 || padding.Horizontal != 0) { //TODO - add another filter just for this, its cumbersome to use final presentation... I think. but maybe theres enough similarities to justify it. - Size size = chain_insize; + Size size = currSize; size.Width += padding.Horizontal; size.Height += padding.Vertical; Filters.FinalPresentation fPadding = new Filters.FinalPresentation(size); @@ -628,10 +652,18 @@ namespace BizHawk.Client.EmuHawk bool simulate = job.simulate; Size chain_outsize = job.chain_outsize; + int vpWidth = videoProvider.BufferWidth; + int vpHeight = videoProvider.BufferHeight; + + //the easiest way to implement crop now is to do it early by adapting the videoprovider + //it might be more performant to integrate it into the filter chain somehow, but that's hard + int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; + int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; + //simulate = true; - int vw = videoProvider.BufferWidth; - int vh = videoProvider.BufferHeight; + int vw = vpWidth; + int vh = vpHeight; if (Global.Config.DispFixAspectRatio) { @@ -647,7 +679,7 @@ namespace BizHawk.Client.EmuHawk } if (Global.Config.DispManagerAR == Config.EDispManagerAR.CustomRatio) { - FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, videoProvider.BufferWidth, videoProvider.BufferHeight, out vw, out vh); + FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, vpWidth, vpHeight, out vw, out vh); } } @@ -657,8 +689,8 @@ namespace BizHawk.Client.EmuHawk int[] videoBuffer = videoProvider.GetVideoBuffer(); - int bufferWidth = videoProvider.BufferWidth; - int bufferHeight = videoProvider.BufferHeight; + int bufferWidth = vpWidth; + int bufferHeight = vpHeight; bool isGlTextureId = videoBuffer.Length == 1; BitmapBuffer bb = null; @@ -669,6 +701,7 @@ namespace BizHawk.Client.EmuHawk { //FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code //is it workable for saturn? + //TODO - this won't respect the user's selected crop. please don't crop this platform or else I'll have to implement this through the videoTexture = GL.WrapGLTexture2d(new IntPtr(videoBuffer[0]), bufferWidth, bufferHeight); } else @@ -685,6 +718,17 @@ namespace BizHawk.Client.EmuHawk } } + ////apply user's choice of cropping + //int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; + //int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; + //bufferWidth -= cropX; + //bufferHeight -= cropY; + + //Art videoTextureArt = new Art(videoTexture); + //videoTextureArt.Width -= cropX; + //videoTextureArt.Height -= cropY; + //videoTextureArt.u + //record the size of what we received, since lua and stuff is gonna want to draw onto it currEmuWidth = bufferWidth; currEmuHeight = bufferHeight; diff --git a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs index 0e12282bd8..1ca514506f 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs @@ -181,9 +181,9 @@ namespace BizHawk.Client.EmuHawk.Filters public eFilterOption FilterOption = eFilterOption.None; public RetroShaderChain BicubicFilter; - public FinalPresentation(Size size) + public FinalPresentation(Size outputSize) { - this.OutputSize = size; + this.OutputSize = outputSize; } Size OutputSize, InputSize; @@ -194,11 +194,14 @@ namespace BizHawk.Client.EmuHawk.Filters public bool Flip; public IGL GL; bool nop; + public Rectangle Crop; LetterboxingLogic LL; Size ContentSize; public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly; + public bool Config_Crop; + /// /// only use with Config_PadOnly /// @@ -223,6 +226,15 @@ namespace BizHawk.Client.EmuHawk.Filters public override Size PresizeInput(string channel, Size size) { + if (Config_Crop) + { + LL = new LetterboxingLogic(); + LL.vx += -Crop.Left; + LL.vy += -Crop.Top; + LL.vw = size.Width - Crop.Width; + LL.vh = size.Height - Crop.Height; + } + if (FilterOption != eFilterOption.Bicubic) return size; @@ -265,7 +277,11 @@ namespace BizHawk.Client.EmuHawk.Filters FindInput().SurfaceDisposition = SurfaceDisposition.Texture; DeclareOutput(new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget)); InputSize = state.SurfaceFormat.Size; - if (Config_PadOnly) + if (Config_Crop) + { + int zzz = 9; + } + else if (Config_PadOnly) { //TODO - redundant fix LL = new LetterboxingLogic(); @@ -286,6 +302,7 @@ namespace BizHawk.Client.EmuHawk.Filters LL.vx += Padding.Left; LL.vy += Padding.Top; } + ContentSize = new Size(LL.vw,LL.vh); if (InputSize == OutputSize) //any reason we need to check vx and vy? @@ -343,7 +360,9 @@ namespace BizHawk.Client.EmuHawk.Filters GuiRenderer.Modelview.Scale(1, -1); GuiRenderer.Modelview.Translate(0, -LL.vh); } - GuiRenderer.Draw(InputTexture,0,0,LL.vw,LL.vh); + if (Config_Crop) + GuiRenderer.Draw(InputTexture, 0, 0, InputSize.Width, InputSize.Height); + else GuiRenderer.Draw(InputTexture, 0, 0, LL.vw, LL.vh); GuiRenderer.End(); } From e53d861db48edc11d3a8807dd6d0b138ee4f64ff Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 18 Jan 2019 01:00:24 -0500 Subject: [PATCH 182/440] Revert "bad attempt at implementing user crop area" --- .../DisplayManager/DisplayManager.cs | 56 ++----------------- .../DisplayManager/Filters/Gui.cs | 27 ++------- 2 files changed, 10 insertions(+), 73 deletions(-) diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index b1fa0804f1..fc7ccbc84b 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -222,30 +222,6 @@ namespace BizHawk.Client.EmuHawk //add the first filter, encompassing output from the emulator core chain.AddFilter(fInput, "input"); - Size currSize = chain_insize; - - //apply user's choice of cropping - //NOTE 1. this is going to break the positioning of elements in lua - //we COULD change how this works to apply it at a different point; but let's wait for someone to ask for it - //we can offer "fix the lua script" as a response, as well, to rebuff them - //NOTE 2. this is an inefficient way of doing it. this could be done if we use 'art' everywhere instead of textures. - //then, we could adjust the uv coords and carry on, rather than doing this extra resolving step. - //Well.... not today - int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; - int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; - if (cropX != 0 || cropY != 0) - { - currSize.Width -= cropX; - currSize.Height -= cropY; - - Filters.FinalPresentation fCrop = new Filters.FinalPresentation(currSize); - fCrop.Config_Crop = true; - fCrop.Crop = new Rectangle(Global.Config.DispCropLeft, Global.Config.DispCropTop, cropX, cropY); - fCrop.GuiRenderer = Renderer; - fCrop.GL = GL; - chain.AddFilter(fCrop, "crop"); - } - //if a non-zero padding is required, add a filter to allow for that //note, we have two sources of padding right now.. one can come from the videoprovider and one from the user. //we're combining these now and just using black, for sake of being lean, despite the discussion below: @@ -255,7 +231,7 @@ namespace BizHawk.Client.EmuHawk if (padding.Vertical != 0 || padding.Horizontal != 0) { //TODO - add another filter just for this, its cumbersome to use final presentation... I think. but maybe theres enough similarities to justify it. - Size size = currSize; + Size size = chain_insize; size.Width += padding.Horizontal; size.Height += padding.Vertical; Filters.FinalPresentation fPadding = new Filters.FinalPresentation(size); @@ -652,18 +628,10 @@ namespace BizHawk.Client.EmuHawk bool simulate = job.simulate; Size chain_outsize = job.chain_outsize; - int vpWidth = videoProvider.BufferWidth; - int vpHeight = videoProvider.BufferHeight; - - //the easiest way to implement crop now is to do it early by adapting the videoprovider - //it might be more performant to integrate it into the filter chain somehow, but that's hard - int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; - int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; - //simulate = true; - int vw = vpWidth; - int vh = vpHeight; + int vw = videoProvider.BufferWidth; + int vh = videoProvider.BufferHeight; if (Global.Config.DispFixAspectRatio) { @@ -679,7 +647,7 @@ namespace BizHawk.Client.EmuHawk } if (Global.Config.DispManagerAR == Config.EDispManagerAR.CustomRatio) { - FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, vpWidth, vpHeight, out vw, out vh); + FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, videoProvider.BufferWidth, videoProvider.BufferHeight, out vw, out vh); } } @@ -689,8 +657,8 @@ namespace BizHawk.Client.EmuHawk int[] videoBuffer = videoProvider.GetVideoBuffer(); - int bufferWidth = vpWidth; - int bufferHeight = vpHeight; + int bufferWidth = videoProvider.BufferWidth; + int bufferHeight = videoProvider.BufferHeight; bool isGlTextureId = videoBuffer.Length == 1; BitmapBuffer bb = null; @@ -701,7 +669,6 @@ namespace BizHawk.Client.EmuHawk { //FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code //is it workable for saturn? - //TODO - this won't respect the user's selected crop. please don't crop this platform or else I'll have to implement this through the videoTexture = GL.WrapGLTexture2d(new IntPtr(videoBuffer[0]), bufferWidth, bufferHeight); } else @@ -718,17 +685,6 @@ namespace BizHawk.Client.EmuHawk } } - ////apply user's choice of cropping - //int cropX = Global.Config.DispCropLeft + Global.Config.DispCropRight; - //int cropY = Global.Config.DispCropTop + Global.Config.DispCropBottom; - //bufferWidth -= cropX; - //bufferHeight -= cropY; - - //Art videoTextureArt = new Art(videoTexture); - //videoTextureArt.Width -= cropX; - //videoTextureArt.Height -= cropY; - //videoTextureArt.u - //record the size of what we received, since lua and stuff is gonna want to draw onto it currEmuWidth = bufferWidth; currEmuHeight = bufferHeight; diff --git a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs index 1ca514506f..0e12282bd8 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs @@ -181,9 +181,9 @@ namespace BizHawk.Client.EmuHawk.Filters public eFilterOption FilterOption = eFilterOption.None; public RetroShaderChain BicubicFilter; - public FinalPresentation(Size outputSize) + public FinalPresentation(Size size) { - this.OutputSize = outputSize; + this.OutputSize = size; } Size OutputSize, InputSize; @@ -194,14 +194,11 @@ namespace BizHawk.Client.EmuHawk.Filters public bool Flip; public IGL GL; bool nop; - public Rectangle Crop; LetterboxingLogic LL; Size ContentSize; public bool Config_FixAspectRatio, Config_FixScaleInteger, Config_PadOnly; - public bool Config_Crop; - /// /// only use with Config_PadOnly /// @@ -226,15 +223,6 @@ namespace BizHawk.Client.EmuHawk.Filters public override Size PresizeInput(string channel, Size size) { - if (Config_Crop) - { - LL = new LetterboxingLogic(); - LL.vx += -Crop.Left; - LL.vy += -Crop.Top; - LL.vw = size.Width - Crop.Width; - LL.vh = size.Height - Crop.Height; - } - if (FilterOption != eFilterOption.Bicubic) return size; @@ -277,11 +265,7 @@ namespace BizHawk.Client.EmuHawk.Filters FindInput().SurfaceDisposition = SurfaceDisposition.Texture; DeclareOutput(new SurfaceState(new SurfaceFormat(OutputSize), SurfaceDisposition.RenderTarget)); InputSize = state.SurfaceFormat.Size; - if (Config_Crop) - { - int zzz = 9; - } - else if (Config_PadOnly) + if (Config_PadOnly) { //TODO - redundant fix LL = new LetterboxingLogic(); @@ -302,7 +286,6 @@ namespace BizHawk.Client.EmuHawk.Filters LL.vx += Padding.Left; LL.vy += Padding.Top; } - ContentSize = new Size(LL.vw,LL.vh); if (InputSize == OutputSize) //any reason we need to check vx and vy? @@ -360,9 +343,7 @@ namespace BizHawk.Client.EmuHawk.Filters GuiRenderer.Modelview.Scale(1, -1); GuiRenderer.Modelview.Translate(0, -LL.vh); } - if (Config_Crop) - GuiRenderer.Draw(InputTexture, 0, 0, InputSize.Width, InputSize.Height); - else GuiRenderer.Draw(InputTexture, 0, 0, LL.vw, LL.vh); + GuiRenderer.Draw(InputTexture,0,0,LL.vw,LL.vh); GuiRenderer.End(); } From b164d8b31cb63e6adb197e445db0983d366a263b Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 18 Jan 2019 01:15:52 -0500 Subject: [PATCH 183/440] implement user crop area as a negative padding fixes #1453 --- BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index fc7ccbc84b..377edac627 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -181,6 +181,13 @@ namespace BizHawk.Client.EmuHawk padding.Bottom += core_padding.Height - core_padding.Height / 2; } + //apply user's crop selections as a negative padding (believe it or not, this largely works) + //is there an issue with the aspect ratio? I dont know--but if there is, there would be with the padding too + padding.Left -= Global.Config.DispCropLeft; + padding.Right -= Global.Config.DispCropRight; + padding.Top -= Global.Config.DispCropTop; + padding.Bottom -= Global.Config.DispCropBottom; + return padding; } From 054048a907d018d277b26d17eda401c7927fb296 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 18 Jan 2019 20:21:13 +1000 Subject: [PATCH 184/440] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d89236f51c..6909b3cdd5 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,9 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag ### GNU+Linux -**IMPORTANT**: The Mono "port" is a work-in-progress! It is *not* complete, does *not* look very nice, and is *not* ready for anything that needs accuracy. +*...or, as I’ve recently taken to calling it, Mono+GNU+Linux.* + +**IMPORTANT**: Linux support is a work-in-progress! It is *not* complete, does *not* look very nice, and is *not* ready for anything that needs accuracy. You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). From 95f45da9dae0160c5f72ffa46834801593c07e19 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 18 Jan 2019 20:24:07 +1000 Subject: [PATCH 185/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6909b3cdd5..be06247a8b 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: Game Boy + GBC (GBHawk), NES (NesHawk), Sega Master System, Atari 7800, Commodore 64, ColecoVision, IntelliVision, TurboGrafx, and ZX Spectrum. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. +If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: GB + GBC (GBHawk), NES (NesHawk), SMS, Atari 7800, and some classic home computers. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From c15916d76a6f3450f8958415f044f2aaec37794f Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 18 Jan 2019 20:27:10 +1000 Subject: [PATCH 186/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be06247a8b..0c5cf4acea 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can run it from anywhere, so putting it in a .desktop file is fine. If running the script doesn't start EmuHawk, you may need to edit it (if you use a terminal, it will say so in the output). -If you run `EmuHawkMono.sh` from a terminal, note that `File > Exit (Alt+F4)` doesn't terminate the process correctly, you'll need to send SIGINT (`^C`). The systems that currently work are: GB + GBC (GBHawk), NES (NesHawk), SMS, Atari 7800, and some classic home computers. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. +The systems that currently work are: GB + GBC (GBHawk), NES (NesHawk), SMS, Atari 7800, and some classic home computers. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. [to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) From ad6790cfb774ee4fe0cc9bfb0866d59f0b976943 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 18 Jan 2019 18:48:50 -0600 Subject: [PATCH 187/440] SubNESHawk: Add subframe reset --- .../Consoles/Nintendo/NES/NES.Core.cs | 9 +++++++++ .../SubNESHawk/SubNESHawk.IEmulator.cs | 18 +++++++++++++++++- .../SubNESHawk/SubNESHawk.IStatable.cs | 4 ++++ .../Consoles/Nintendo/SubNESHawk/SubNESHawk.cs | 4 +++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 40d3106894..ac9f0d3b26 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -197,6 +197,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } + // Add in the reset timing float control for subneshawk + if (using_reset_timing && (ControllerDefinition.FloatControls.Count() == 0)) + { + ControllerDefinition.FloatControls.Add("Reset Cycle"); + ControllerDefinition.FloatRanges.Add(new ControllerDefinition.FloatRange(0, 0, 500000)); + } + // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); @@ -419,6 +426,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public bool current_strobe; public bool new_strobe; public bool alt_lag; + // variable used with subneshawk to trigger reset at specific cycle after reset + public bool using_reset_timing = false; // this function will run one step of the ppu // it will return whether the controller is read or not. public void do_single_step(IController controller, out bool cont_read, out bool frame_done) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs index 106ebbd9b6..25a5a0b632 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -30,11 +30,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk HardReset(); } + reset_frame = false; if (controller.IsPressed("Reset")) { - SoftReset(); + reset_frame = true; } + reset_cycle = controller.GetFloat("Reset Cycle"); + reset_cycle_int = (int)Math.Floor(reset_cycle); + _islag = true; subnes.alt_lag = true; @@ -47,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk if (pass_a_frame) { subnes.videoProvider.FillFrameBuffer(); + current_cycle = 0; } _islag = subnes.alt_lag; @@ -57,19 +62,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk VBL_CNT++; } + reset_frame = false; return ret; } public bool stop_cur_frame; public bool pass_new_input; public bool pass_a_frame; + public bool reset_frame; + public int current_cycle; + public float reset_cycle; + public int reset_cycle_int; public void do_frame(IController controller) { stop_cur_frame = false; while (!stop_cur_frame) { + if (reset_frame && (current_cycle == reset_cycle_int)) + { + SoftReset(); + reset_frame = false; + } subnes.do_single_step(controller, out pass_new_input, out pass_a_frame); + current_cycle++; stop_cur_frame |= pass_a_frame; stop_cur_frame |= pass_new_input; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs index 201b6d584e..110e5274b0 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IStatable.cs @@ -53,7 +53,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk ser.Sync("Frame", ref _frame); ser.Sync("IsLag", ref _islag); ser.Sync("pass_a_frame", ref pass_a_frame); + ser.Sync("reset_frame", ref reset_frame); ser.Sync("pass_new_input", ref pass_new_input); + ser.Sync("current_cycle", ref current_cycle); + ser.Sync("reset_cycle", ref reset_cycle); + ser.Sync("reset_cycle_int", ref reset_cycle_int); ser.Sync("VBL_CNT", ref VBL_CNT); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index 05c61c4680..2bbf28d1fb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -43,8 +43,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk SetupMemoryDomains(); + subnes.using_reset_timing = true; HardReset(); - + current_cycle = 0; VBL_CNT = 0; } @@ -59,6 +60,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk subnes.cpu.NESSoftReset(); subnes.apu.NESSoftReset(); subnes.ppu.NESSoftReset(); + current_cycle = 0; } public DisplayType Region => DisplayType.NTSC; From 8e99908c4776c36ab7f3ab4dcbc39cd4074c2524 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 19 Jan 2019 09:23:22 -0600 Subject: [PATCH 188/440] SubNESHawk: Add ppu cycle to tracer --- BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs | 9 +++++++-- .../Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs | 2 ++ .../Consoles/Nintendo/SubNESHawk/SubNESHawk.cs | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs b/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs index 83d94aad78..2b0965e0ed 100644 --- a/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs +++ b/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs @@ -74,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 "{0:X4}: {1,-9} {2} ", PC, rawbytes, disasm).PadRight(32), RegisterInfo = string.Format( - "A:{0:X2} X:{1:X2} Y:{2:X2} SP:{4:X2} P:{3:X2} {6}{7}{8}{9}{10}{11}{12}{13} Cy:{5}", + "A:{0:X2} X:{1:X2} Y:{2:X2} SP:{4:X2} P:{3:X2} {6}{7}{8}{9}{10}{11}{12}{13} Cy:{5} PPU-Cy:{15}", A, X, Y, P, S, TotalExecutedCycles, FlagN ? "N" : "n", FlagV ? "V" : "v", @@ -84,7 +84,8 @@ namespace BizHawk.Emulation.Cores.Components.M6502 FlagI ? "I" : "i", FlagZ ? "Z" : "z", FlagC ? "C" : "c", - !RDY ? "R" : "r") + !RDY ? "R" : "r", + ext_ppu_cycle) }; } @@ -120,6 +121,9 @@ namespace BizHawk.Emulation.Cores.Components.M6502 public bool NMI; public bool RDY; + // ppu cycle (used with SubNESHawk) + public int ext_ppu_cycle = 0; + public void SyncState(Serializer ser) { ser.BeginSection("MOS6502X"); @@ -143,6 +147,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 ser.Sync("interrupt_pending", ref interrupt_pending); ser.Sync("branch_irq_hack", ref branch_irq_hack); ser.Sync("rdy_freeze", ref rdy_freeze); + ser.Sync("ext_ppu_cycle", ref ext_ppu_cycle); ser.EndSection(); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs index 25a5a0b632..ba5b1c0638 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.IEmulator.cs @@ -52,6 +52,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk { subnes.videoProvider.FillFrameBuffer(); current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; } _islag = subnes.alt_lag; @@ -86,6 +87,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk } subnes.do_single_step(controller, out pass_new_input, out pass_a_frame); current_cycle++; + subnes.cpu.ext_ppu_cycle = current_cycle; stop_cur_frame |= pass_a_frame; stop_cur_frame |= pass_new_input; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index 2bbf28d1fb..d74af9ed40 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -36,7 +36,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk ser.Register(subnes.videoProvider); ser.Register(subnes.magicSoundProvider); - _tracer = new TraceBuffer { Header = subnes.cpu.TraceHeader }; + _tracer = new TraceBuffer { Header = "6502: PC, machine code, mnemonic, operands, registers (A, X, Y, P, SP), flags (NVTBDIZCR), CPU Cycle, PPU Cycle" }; ser.Register(_tracer); ServiceProvider = ser; @@ -46,6 +46,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk subnes.using_reset_timing = true; HardReset(); current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; VBL_CNT = 0; } @@ -61,6 +62,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk subnes.apu.NESSoftReset(); subnes.ppu.NESSoftReset(); current_cycle = 0; + subnes.cpu.ext_ppu_cycle = current_cycle; } public DisplayType Region => DisplayType.NTSC; From 2bddf3663e0b48dc53c01fb55dd61eaa733292c5 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 19 Jan 2019 13:30:42 -0600 Subject: [PATCH 189/440] TAStudio: Fix some bugs in new from menues --- .../conversions/MovieConversionExtensions.cs | 24 +++++++++++++++++-- .../movie/tasproj/TasStateManager.cs | 12 +++++++++- .../tools/TAStudio/TAStudio.MenuItems.cs | 22 ++++++++++------- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs index 0cd32aa7ef..99716f7617 100644 --- a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs +++ b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs @@ -126,7 +126,17 @@ namespace BizHawk.Client.Common.MovieConversionExtensions public static TasMovie ConvertToSavestateAnchoredMovie(this TasMovie old, int frame, byte[] savestate) { - string newFilename = old.Filename + "." + TasMovie.Extension; + string newFilename = old.Filename; + + if (old.Filename.Contains("tasproj")) + { + newFilename = newFilename.Remove(newFilename.Length - 7, 7); + newFilename = newFilename + "nfn." + TasMovie.Extension; + } + else + { + newFilename = old.Filename + "." + TasMovie.Extension; + } if (File.Exists(newFilename)) { @@ -201,7 +211,17 @@ namespace BizHawk.Client.Common.MovieConversionExtensions public static TasMovie ConvertToSaveRamAnchoredMovie(this TasMovie old, byte[] saveRam) { - string newFilename = old.Filename + "." + TasMovie.Extension; + string newFilename = old.Filename; + + if (old.Filename.Contains("tasproj")) + { + newFilename = newFilename.Remove(newFilename.Length - 7, 7); + newFilename = newFilename + "nfsr." + TasMovie.Extension; + } + else + { + newFilename = old.Filename + "." + TasMovie.Extension; + } if (File.Exists(newFilename)) { diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index 3b2920814c..671fb95c05 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -384,7 +384,17 @@ namespace BizHawk.Client.Common { if (_states.Any()) { - StateManagerState power = _states.Values.First(s => s.Frame == 0); + var temp_state = _states.Values; + StateManagerState power = null; + if (temp_state[0].Frame==0) + { + power = _states.Values.First(s => s.Frame == 0); + } + else + { + power = _states.Values[0]; + } + _states.Clear(); SetState(0, power.State); Used = (ulong)power.State.Length; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index f2eb9db437..9097bb66f4 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -1453,14 +1453,20 @@ namespace BizHawk.Client.EmuHawk { if (AskSaveChanges()) { - int index = TasView.SelectedRows.First(); - GoToFrame(index); - - TasMovie newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie( - SaveRamEmulator.CloneSaveRam()); - - Mainform.PauseEmulator(); - LoadFile(new FileInfo(newProject.Filename), true); + if (SaveRamEmulator.CloneSaveRam() != null) + { + int index = 0; + if (TasView.SelectedRows.Count() > 0) { index = TasView.SelectedRows.First(); } + GoToFrame(index); + TasMovie newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie( + SaveRamEmulator.CloneSaveRam()); + Mainform.PauseEmulator(); + LoadFile(new FileInfo(newProject.Filename), true); + } + else + { + throw new Exception("No SaveRam"); + } } } From 6e1a19b5f864da039f92ef42f96942a220190173 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 19 Jan 2019 14:02:45 -0600 Subject: [PATCH 190/440] TAStudio: Ask to override existing bk2 file when exporting --- .../tools/TAStudio/TAStudio.MenuItems.cs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 9097bb66f4..be508b1bc9 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -267,17 +267,41 @@ namespace BizHawk.Client.EmuHawk private void ToBk2MenuItem_Click(object sender, EventArgs e) { _autosaveTimer.Stop(); - var bk2 = CurrentTasMovie.ToBk2(true); + var bk2 = CurrentTasMovie.ToBk2(true, true); MessageStatusLabel.Text = "Exporting to .bk2..."; Cursor = Cursors.WaitCursor; Update(); - bk2.Save(); + string d_exp = " not exported."; + var file = new FileInfo(bk2.Filename); + if (file.Exists) + { + GlobalWin.Sound.StopSound(); + var result = MessageBox.Show( + "Overwrite Existing File?", + "Tastudio", + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Question, + MessageBoxDefaultButton.Button3); + + GlobalWin.Sound.StartSound(); + if (result == DialogResult.Yes) + { + bk2.Save(); + d_exp = " exported."; + } + } + else + { + bk2.Save(); + d_exp = " exported."; + } + if (Settings.AutosaveInterval > 0) { _autosaveTimer.Start(); } - MessageStatusLabel.Text = bk2.Name + " exported."; + MessageStatusLabel.Text = bk2.Name + d_exp; Cursor = Cursors.Default; } From c4b3a7c3b8b6b5991f65ac10a9299a2aa153cd50 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 19 Jan 2019 14:47:12 -0600 Subject: [PATCH 191/440] TAStudio: Update window name when using saveas, Fixes #1444 --- BizHawk.Client.EmuHawk/MainForm.cs | 2 +- BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index c93ebb1d99..a3d9533159 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -1428,7 +1428,7 @@ namespace BizHawk.Client.EmuHawk } } - private void SetWindowText() + public void SetWindowText() { string str = ""; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index be508b1bc9..61ec0e85bb 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -169,6 +169,7 @@ namespace BizHawk.Client.EmuHawk _autosaveTimer.Start(); } + Mainform.SetWindowText(); GlobalWin.Sound.StartSound(); } From 0ee9ddc9aaef35375c7f456b3ff25b08099780ac Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 20 Jan 2019 02:30:19 -0500 Subject: [PATCH 192/440] for some reason in 482a3ab8f6af9dfbd75ff84694bdfbce8ade62f1 I changed the sln to have x64 and x86 projects instead of anycpu. maybe I had a good reason for that, but I didn't write it in that commit, and so I'm reverting this until someone articulates a good reason --- BizHawk.sln | 120 ---------------------------------------------------- 1 file changed, 120 deletions(-) diff --git a/BizHawk.sln b/BizHawk.sln index 7db07c23e3..2b1a0659ef 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -62,189 +62,69 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x64.ActiveCfg = Debug|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x64.Build.0 = Debug|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x86.ActiveCfg = Debug|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Debug|x86.Build.0 = Debug|Any CPU {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Any CPU.ActiveCfg = Release|Any CPU {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|Any CPU.Build.0 = Release|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x64.ActiveCfg = Release|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x64.Build.0 = Release|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x86.ActiveCfg = Release|Any CPU - {0CE8B337-08E3-4602-BF10-C4D4C75D2F13}.Release|x86.Build.0 = Release|Any CPU {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x64.ActiveCfg = Debug|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x64.Build.0 = Debug|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x86.ActiveCfg = Debug|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Debug|x86.Build.0 = Debug|Any CPU {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Any CPU.ActiveCfg = Release|Any CPU {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|Any CPU.Build.0 = Release|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x64.ActiveCfg = Release|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x64.Build.0 = Release|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x86.ActiveCfg = Release|Any CPU - {24A0AA3C-B25F-4197-B23D-476D6462DBA0}.Release|x86.Build.0 = Release|Any CPU {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x64.ActiveCfg = Debug|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x64.Build.0 = Debug|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x86.ActiveCfg = Debug|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Debug|x86.Build.0 = Debug|Any CPU {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Any CPU.Build.0 = Release|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x64.ActiveCfg = Release|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x64.Build.0 = Release|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.ActiveCfg = Release|Any CPU - {866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.Build.0 = Release|Any CPU {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x64.ActiveCfg = Debug|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x64.Build.0 = Debug|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.ActiveCfg = Debug|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.Build.0 = Debug|Any CPU {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.Build.0 = Release|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x64.ActiveCfg = Release|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x64.Build.0 = Release|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.ActiveCfg = Release|Any CPU - {DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.Build.0 = Release|Any CPU {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x64.ActiveCfg = Debug|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x64.Build.0 = Debug|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.ActiveCfg = Debug|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.Build.0 = Debug|Any CPU {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.Build.0 = Release|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x64.ActiveCfg = Release|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x64.Build.0 = Release|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.ActiveCfg = Release|Any CPU - {C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.Build.0 = Release|Any CPU {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x64.ActiveCfg = Debug|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x64.Build.0 = Debug|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x86.ActiveCfg = Debug|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|x86.Build.0 = Debug|Any CPU {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Any CPU.ActiveCfg = Release|Any CPU {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|Any CPU.Build.0 = Release|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x64.ActiveCfg = Release|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x64.Build.0 = Release|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x86.ActiveCfg = Release|Any CPU - {F51946EA-827F-4D82-B841-1F2F6D060312}.Release|x86.Build.0 = Release|Any CPU {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x64.ActiveCfg = Debug|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x64.Build.0 = Debug|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x86.ActiveCfg = Debug|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Debug|x86.Build.0 = Debug|Any CPU {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1A23168-B571-411C-B360-2229E7225E0E}.Release|Any CPU.Build.0 = Release|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x64.ActiveCfg = Release|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x64.Build.0 = Release|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x86.ActiveCfg = Release|Any CPU - {E1A23168-B571-411C-B360-2229E7225E0E}.Release|x86.Build.0 = Release|Any CPU {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x64.ActiveCfg = Debug|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x64.Build.0 = Debug|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x86.ActiveCfg = Debug|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Debug|x86.Build.0 = Debug|Any CPU {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Any CPU.ActiveCfg = Release|Any CPU {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|Any CPU.Build.0 = Release|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x64.ActiveCfg = Release|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x64.Build.0 = Release|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x86.ActiveCfg = Release|Any CPU - {197D4314-8A9F-49BA-977D-54ACEFAEB6BA}.Release|x86.Build.0 = Release|Any CPU {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x64.ActiveCfg = Debug|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x64.Build.0 = Debug|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x86.ActiveCfg = Debug|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Debug|x86.Build.0 = Debug|Any CPU {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Any CPU.ActiveCfg = Release|Any CPU {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|Any CPU.Build.0 = Release|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x64.ActiveCfg = Release|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x64.Build.0 = Release|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x86.ActiveCfg = Release|Any CPU - {9F84A0B2-861E-4EF4-B89B-5E2A3F38A465}.Release|x86.Build.0 = Release|Any CPU {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x64.ActiveCfg = Debug|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x64.Build.0 = Debug|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x86.ActiveCfg = Debug|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Debug|x86.Build.0 = Debug|Any CPU {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Any CPU.ActiveCfg = Release|Any CPU {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Any CPU.Build.0 = Release|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x64.ActiveCfg = Release|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x64.Build.0 = Release|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.ActiveCfg = Release|Any CPU - {5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.Build.0 = Release|Any CPU {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x64.ActiveCfg = Debug|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x64.Build.0 = Debug|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.ActiveCfg = Debug|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.Build.0 = Debug|Any CPU {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Any CPU.Build.0 = Release|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x64.ActiveCfg = Release|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x64.Build.0 = Release|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.ActiveCfg = Release|Any CPU - {2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.Build.0 = Release|Any CPU {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Any CPU.Build.0 = Debug|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x64.ActiveCfg = Debug|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x64.Build.0 = Debug|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x86.ActiveCfg = Debug|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|x86.Build.0 = Debug|Any CPU {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Any CPU.ActiveCfg = Release|Any CPU {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|Any CPU.Build.0 = Release|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x64.ActiveCfg = Release|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x64.Build.0 = Release|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x86.ActiveCfg = Release|Any CPU - {337CA23E-65E7-44E1-9411-97EE08BB8116}.Release|x86.Build.0 = Release|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x64.ActiveCfg = Debug|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x64.Build.0 = Debug|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x86.ActiveCfg = Debug|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|x86.Build.0 = Debug|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Any CPU.ActiveCfg = Release|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Any CPU.Build.0 = Release|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x64.ActiveCfg = Release|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x64.Build.0 = Release|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x86.ActiveCfg = Release|Any CPU - {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|x86.Build.0 = Release|Any CPU {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|x64.ActiveCfg = Debug|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|x86.ActiveCfg = Debug|Any CPU {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Any CPU.ActiveCfg = Release|Any CPU {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Any CPU.Build.0 = Release|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|x64.ActiveCfg = Release|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|x86.ActiveCfg = Release|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x64.ActiveCfg = Debug|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x64.Build.0 = Debug|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x86.ActiveCfg = Debug|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|x86.Build.0 = Debug|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.Build.0 = Release|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x64.ActiveCfg = Release|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x64.Build.0 = Release|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.ActiveCfg = Release|Any CPU - {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 0114e39489e3ba33836f8cfdaa230aa9bef077ea Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sun, 20 Jan 2019 09:20:52 -0500 Subject: [PATCH 193/440] change all uses of -c:a libvo_aac to -c:a aac because the ffmpeg we're packaging now no longer supports the former --- BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs index 12d526efd0..004c288d58 100644 --- a/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs +++ b/BizHawk.Client.EmuHawk/AVOut/FFmpegWriterForm.cs @@ -59,7 +59,7 @@ namespace BizHawk.Client.EmuHawk new FormatPreset("Matroska", "AVC video and Vorbis audio in a Matroska container.", "-c:a libvorbis -c:v libx264 -f matroska", false, "mkv"), new FormatPreset("MP4", "AVC video and AAC audio in an MP4 container.", - "-c:a libvo_aacenc -c:v libx264 -f mp4", false, "mp4"), + "-c:a aac -c:v libx264 -f mp4", false, "mp4"), new FormatPreset("WebM", "VP8 video and Vorbis audio in a WebM container.", "-c:a libvorbis -c:v libvpx -f webm", false, "webm"), new FormatPreset("Ogg", "Theora video and Vorbis audio in an Ogg contrainer.", @@ -67,9 +67,9 @@ namespace BizHawk.Client.EmuHawk new FormatPreset("Xvid", "Xvid video and MP3 audio in an AVI container.", "-c:a libmp3lame -c:v libxvid -f avi", false, "avi"), new FormatPreset("QuickTime", "AVC video and AAC audio in a QuickTime container.", - "-c:a libvo_aacenc -c:v libx264 -f mov", false, "mov"), + "-c:a aac -c:v libx264 -f mov", false, "mov"), new FormatPreset("FLV", "AVC video and AAC audio in a Flash Video container.", - "-c:a libvo_aacenc -c:v libx264 -f flv", false, "flv"), + "-c:a aac -c:v libx264 -f flv", false, "flv"), new FormatPreset("[Custom]", "Write your own ffmpeg command. For advanced users only.", "-c:a foo -c:v bar -f baz", true, "foobar"), }; From 64c3b9dcd288710c140e0927f2a47ec0d14fb139 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 20 Jan 2019 09:06:25 -0600 Subject: [PATCH 194/440] NESHawk: Implement newly found APU behaviour --- BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs index 303073dfbc..d39606def4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs @@ -704,6 +704,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES sample_buffer_filled = false; out_deltacounter = 64; out_bits_remaining = 0; + user_address = 0x8000; // even though this can't be accessed by writing, it is indeed the power up address + user_length = 1; } bool irq_enabled; From a15e85639049ef50694abedd0aa41b5e65babc7a Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 20 Jan 2019 09:30:08 -0600 Subject: [PATCH 195/440] Update link text to match link status --- BizHawk.Client.EmuHawk/MainForm.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 09f671b765..ff80757b3d 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2658,6 +2658,10 @@ namespace BizHawk.Client.EmuHawk LinkConnectStatusBarButton.Image = Emulator.AsLinkable().LinkConnected ? _linkCableOn : _linkCableOff; + + LinkConnectStatusBarButton.ToolTipText = Emulator.AsLinkable().LinkConnected + ? "Link connection is currently enabled" + : "Link connection is currently disabled"; } else { From e50272f9f4811bd8d6e39072fda5f09b254f49e6 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 20 Jan 2019 10:12:06 -0600 Subject: [PATCH 196/440] GBHawkLink: Fix frame display when loading a state --- .../Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index df9029b226..5187308752 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -148,11 +148,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { buff_L = L.GetVideoBuffer(); L.vblank_rise = false; + FillVideoBuffer(); } if (R.vblank_rise) { buff_R = R.GetVideoBuffer(); R.vblank_rise = false; + FillVideoBuffer(); } } } @@ -194,6 +196,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public int[] buff_R = new int[160 * 144]; public int[] GetVideoBuffer() + { + return _vidbuffer; + } + + public void FillVideoBuffer() { // combine the 2 video buffers from the instances for (int i = 0; i < 144; i++) @@ -202,10 +209,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { _vidbuffer[i * 320 + j] = buff_L[i * 160 + j]; _vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j]; - } + } } - - return _vidbuffer; } public int VirtualWidth => 160 * 2; From f65959f64c5e2663be086710c361b1f183d01da6 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 21 Jan 2019 14:13:32 -0600 Subject: [PATCH 197/440] SubNESHawk: Pass through memory domains --- .../Consoles/Nintendo/NES/NES.IMemoryDomains.cs | 2 +- .../Consoles/Nintendo/SubNESHawk/SubNESHawk.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IMemoryDomains.cs index 0997f6e269..30d37f6e20 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IMemoryDomains.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { public partial class NES { - private MemoryDomainList _memoryDomains; + public MemoryDomainList _memoryDomains; private bool _memoryDomainsSetup = false; private void SetupMemoryDomains() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index d74af9ed40..bc20055601 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -41,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk ServiceProvider = ser; - SetupMemoryDomains(); + (ServiceProvider as BasicServiceProvider).Register(subnes._memoryDomains); subnes.using_reset_timing = true; HardReset(); From 40384b0103efbf778adbe07498c7715d580e15fa Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 22 Jan 2019 16:48:39 +0000 Subject: [PATCH 198/440] ApiHawk: fixed incorrect case in GUIApi.cs (causing BizHawk not to build on case-intolerant linux) --- BizHawk.Client.EmuHawk/Api/Libraries/{GUIApi.cs => GuiApi.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BizHawk.Client.EmuHawk/Api/Libraries/{GUIApi.cs => GuiApi.cs} (100%) diff --git a/BizHawk.Client.EmuHawk/Api/Libraries/GUIApi.cs b/BizHawk.Client.EmuHawk/Api/Libraries/GuiApi.cs similarity index 100% rename from BizHawk.Client.EmuHawk/Api/Libraries/GUIApi.cs rename to BizHawk.Client.EmuHawk/Api/Libraries/GuiApi.cs From f2938d4895ff1af819a4252c81740b0a35c231e0 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 23 Jan 2019 02:58:24 +1000 Subject: [PATCH 199/440] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0c5cf4acea..83d47375b1 100644 --- a/README.md +++ b/README.md @@ -171,11 +171,9 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn #### Loading firmware -You may have seen a dialog saying "You are missing the needed firmware files [...]" when trying to open a rom. Pressing "Yes" opens the Firmware Manager, or you can go to `Config` > `Firmwares...`. +The easiest way to get BizHawk to use your firmwares is to go to `Config` > `Paths...`, and change "Firmware" in the "Global" tab to be the location of them (choose the folder where they're saved). -To load firmwares, the easiest way is to click "Import" in the menubar, navigate to the dumped firmware(s), select them all, and click "Open". It's a good idea to have them copied into the `Firmware` folder, which is nicely organised, when prompted. If you were trying to open a rom, click "Close and reload ROM" to do that. Keep in mind some firmware is optional and some have multiple versions, only one of which needs to be set. - -Windows users can keep the `Firmware` folder made by the firmware manager when updating, go to `Config` > `Paths...` and change "Firmware" under "Global" to point at it. +If your firmware is scattered, you can load them individually with the Firmware Manager. Open it by choosing "Yes" in the "You are missing the needed firmware files [...]" dialog (when trying to open a rom), or by going to `Config` > `Firmwares...`. Right-click the line of the firmware you want to load, click "", and open the file to load it. Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. #### Identifying a good rom From 9b145c27afd14a954ae24958f2b8e5cc23b32127 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 23 Jan 2019 16:54:07 +1000 Subject: [PATCH 200/440] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 83d47375b1..0081bf1f96 100644 --- a/README.md +++ b/README.md @@ -171,9 +171,11 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn #### Loading firmware -The easiest way to get BizHawk to use your firmwares is to go to `Config` > `Paths...`, and change "Firmware" in the "Global" tab to be the location of them (choose the folder where they're saved). +The easiest way to get BizHawk to use your firmwares is to go to `Config` > `Paths...`, and change "Firmware" in the "Global" tab to be their location (choose the *folder* where they're saved). -If your firmware is scattered, you can load them individually with the Firmware Manager. Open it by choosing "Yes" in the "You are missing the needed firmware files [...]" dialog (when trying to open a rom), or by going to `Config` > `Firmwares...`. Right-click the line of the firmware you want to load, click "", and open the file to load it. Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. +If your firmware is scattered, you can load them individually with the Firmware Manager. Open it by choosing "Yes" in the "You are missing the needed firmware files [...]" dialog (when trying to open a rom), or by going to `Config` > `Firmwares...`. Right-click the line of the firmware you want to load, click "Set Customization", and choose the file in the dialog to load it. + +Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. #### Identifying a good rom From 21401636f124e55ac12b98500c6c08a12801a3c7 Mon Sep 17 00:00:00 2001 From: feos Date: Wed, 23 Jan 2019 13:23:25 +0300 Subject: [PATCH 201/440] Update README.md Come one, was it so hard? --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0081bf1f96..52ccf8ad61 100644 --- a/README.md +++ b/README.md @@ -171,11 +171,13 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn #### Loading firmware -The easiest way to get BizHawk to use your firmwares is to go to `Config` > `Paths...`, and change "Firmware" in the "Global" tab to be their location (choose the *folder* where they're saved). +Put all your firmware to BizHawk's `Firmware` folder. All the needed firmware images will be automatically detected and loaded when you launch EmuHawk. File names and directory tree don't matter, because it's scanning the hashsums and picks the needed files according to its firmware database. -If your firmware is scattered, you can load them individually with the Firmware Manager. Open it by choosing "Yes" in the "You are missing the needed firmware files [...]" dialog (when trying to open a rom), or by going to `Config` > `Firmwares...`. Right-click the line of the firmware you want to load, click "Set Customization", and choose the file in the dialog to load it. +If you want to customize firmware (for example, when you need to select a specific firmware version) go to `Config` > `Firmwares...`, right-click the line of the firmware you want to change, click "Set Customization", and choose the file in the dialog to load it. Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. -Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. +You can change the folder to scan for firmware (for example, if you want several BizHawk releases to share the same firmware folder) by going to `Config` > `Paths...` and changing "Firmware" in the "Global" tab to the new location. + +If the firmware needed for a system can't be found, you will see the "You are missing the needed firmware files [...]" dialog when trying to open a game. #### Identifying a good rom From 248ed700a216a91945a29df781e6562f4e943080 Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 23 Jan 2019 20:38:05 +1000 Subject: [PATCH 202/440] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 52ccf8ad61..36c99889e9 100644 --- a/README.md +++ b/README.md @@ -171,13 +171,13 @@ Again, if your distro isn't listed there, you might get an "Unknown distro" warn #### Loading firmware -Put all your firmware to BizHawk's `Firmware` folder. All the needed firmware images will be automatically detected and loaded when you launch EmuHawk. File names and directory tree don't matter, because it's scanning the hashsums and picks the needed files according to its firmware database. +Put all your dumped firmware files in the `Firmware` folder and everything will be automatically detected and loaded when you try to load a game (filenames and subfolders aren't enforced, you can just throw them in there). If you're missing required or optional firmware, you will see a "You are missing the needed firmware files [...]" dialog. -If you want to customize firmware (for example, when you need to select a specific firmware version) go to `Config` > `Firmwares...`, right-click the line of the firmware you want to change, click "Set Customization", and choose the file in the dialog to load it. Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. +Keep in mind some firmware is optional, and some have multiple versions, only one of which needs to be set. -You can change the folder to scan for firmware (for example, if you want several BizHawk releases to share the same firmware folder) by going to `Config` > `Paths...` and changing "Firmware" in the "Global" tab to the new location. +If you want to customise firmware (when there are alternative firmwares, for example) go to `Config` > `Firmwares...`, right-click the line of the firmware you want to change, click "Set Customization", and open the file. -If the firmware needed for a system can't be found, you will see the "You are missing the needed firmware files [...]" dialog when trying to open a game. +You can change where BizHawk looks for firmware by going to `Config` > `Paths...` and changing "Firmware" in the "Global" tab to the new location. This allows multiple versions to use the same folder. #### Identifying a good rom From a7518d4e32cf9be7e68537957b689bd07a95b4df Mon Sep 17 00:00:00 2001 From: James Groom Date: Wed, 23 Jan 2019 20:43:32 +1000 Subject: [PATCH 203/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36c99889e9..2f71078672 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Keep in mind some firmware is optional, and some have multiple versions, only on If you want to customise firmware (when there are alternative firmwares, for example) go to `Config` > `Firmwares...`, right-click the line of the firmware you want to change, click "Set Customization", and open the file. -You can change where BizHawk looks for firmware by going to `Config` > `Paths...` and changing "Firmware" in the "Global" tab to the new location. This allows multiple versions to use the same folder. +You can change where BizHawk looks for firmware by going to `Config` > `Paths...` and changing "Firmware" in the "Global" tab to the new location. This allows multiple BizHawk releases to use the same folder. #### Identifying a good rom From ce3e3d2ed37ab890b3baf97d9d6ce4ce8a4e0379 Mon Sep 17 00:00:00 2001 From: feos Date: Wed, 23 Jan 2019 15:41:26 +0300 Subject: [PATCH 204/440] lua docs: couple hints --- BizHawk.Client.Common/lua/LuaDocumentation.cs | 4 ++-- .../tools/Lua/Libraries/EmuLuaLibrary.Gui.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.Common/lua/LuaDocumentation.cs b/BizHawk.Client.Common/lua/LuaDocumentation.cs index c52c4316fb..2fa7471105 100644 --- a/BizHawk.Client.Common/lua/LuaDocumentation.cs +++ b/BizHawk.Client.Common/lua/LuaDocumentation.cs @@ -26,10 +26,10 @@ __Types and notation__ * ? (question mark) ** A question mark next to a value indicates that it is a Nullable type (only applies to types that are not normally nullable) * [[]] (brackets) -** Brackets around a parameter indicate that the parameter is optional. optional parameters have an equals sign followed by the value that will be used if no value is supplied. +** Brackets around a parameter indicate that the parameter is optional. Optional parameters have an equals sign followed by the value that will be used if no value is supplied. ** Brackets after a parameter type indicate it is an array * null -** null is equivalent to the lua nil +** null is equivalent to the lua nil. Lua doesn't support named arguments, it checks the arguments by position. So if you're sending an optional argument that goes ''after'' other optional arguments you don't want to send, replace those with lua nil. * Color ** This is a .NET System.Drawing.Color struct. The value passed from lua is any value acceptable in the Color constructor. This means either a string with the color name such as ""red"", or a 0xAARRGGBB integer value. Unless specified, this is not a nullable value * object diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Gui.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Gui.cs index 814c5ea53f..9775b41c28 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Gui.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Gui.cs @@ -511,7 +511,7 @@ namespace BizHawk.Client.EmuHawk } [LuaMethodExample("gui.drawText( 16, 32, \"Some message\", 0x7F0000FF, 0x00007FFF, 8, \"Arial Narrow\", \"bold\", \"center\", \"middle\" );")] - [LuaMethod("drawText", "Draws the given message in the emulator screen space (like all draw functions) at the given x,y coordinates and the given color. The default color is white. A fontfamily can be specified and is monospace generic if none is specified (font family options are the same as the .NET FontFamily class). The fontsize default is 12. The default font style is regular. Font style options are regular, bold, italic, strikethrough, underline. Horizontal alignment options are left (default), center, or right. Vertical alignment options are bottom (default), middle, or top. Alignment options specify which ends of the text will be drawn at the x and y coordinates.")] + [LuaMethod("drawText", "Draws the given message in the emulator screen space (like all draw functions) at the given x,y coordinates and the given color. The default color is white. A fontfamily can be specified and is monospace generic if none is specified (font family options are the same as the .NET FontFamily class). The fontsize default is 12. The default font style is regular. Font style options are regular, bold, italic, strikethrough, underline. Horizontal alignment options are left (default), center, or right. Vertical alignment options are bottom (default), middle, or top. Alignment options specify which ends of the text will be drawn at the x and y coordinates. For pixel-perfect font look, make sure to disable aspect ratio correction.")] public void DrawText( int x, int y, From 9955c55a0a700f193319a6e6b48548c72231b2f4 Mon Sep 17 00:00:00 2001 From: feos Date: Wed, 23 Jan 2019 16:07:34 +0300 Subject: [PATCH 205/440] address #1458 --- .../CPUs/68000/Instructions/IntegerMath.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/68000/Instructions/IntegerMath.cs b/BizHawk.Emulation.Cores/CPUs/68000/Instructions/IntegerMath.cs index 6d53ae61bc..46dfbd7ce8 100644 --- a/BizHawk.Emulation.Cores/CPUs/68000/Instructions/IntegerMath.cs +++ b/BizHawk.Emulation.Cores/CPUs/68000/Instructions/IntegerMath.cs @@ -189,7 +189,7 @@ namespace BizHawk.Emulation.Cores.Components.M68000 int pc = info.PC + 2; int size = (op >> 6) & 3; int mode = (op >> 3) & 7; - int reg = (op >> 0) & 3; + int reg = (op >> 0) & 7; switch (size) { @@ -516,7 +516,7 @@ namespace BizHawk.Emulation.Cores.Components.M68000 int pc = info.PC + 2; int size = (op >> 6) & 3; int mode = (op >> 3) & 7; - int reg = (op >> 0) & 3; + int reg = (op >> 0) & 7; switch (size) { @@ -1147,4 +1147,4 @@ namespace BizHawk.Emulation.Cores.Components.M68000 info.Length = pc - info.PC; } } -} \ No newline at end of file +} From 766de68e188d06468c2a1a2df7af2c19bf4f97d9 Mon Sep 17 00:00:00 2001 From: feos Date: Wed, 23 Jan 2019 17:24:21 +0300 Subject: [PATCH 206/440] tastudio: don't tell about clipboard if it's empty --- BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 8b0647d1f6..1462a28b47 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -990,8 +990,9 @@ namespace BizHawk.Client.EmuHawk "Selected: " + TasView.SelectedRows.Count() + " frame" + (TasView.SelectedRows.Count() == 1 ? "" : "s") + ", States: " + CurrentTasMovie.TasStateManager.StateCount.ToString() + - ", Clipboard: " + (_tasClipboard.Any() ? _tasClipboard.Count + " frame" + - (_tasClipboard.Count == 1 ? "" : "s") : "empty"); + (_tasClipboard.Any() + ? ", Clipboard: " + _tasClipboard.Count + " frame" + (_tasClipboard.Count == 1 ? "" : "s") + : ""); } private void UpdateChangesIndicator() From a8f293eec8ae4e9a5008912fed57bd3586e90e91 Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Thu, 24 Jan 2019 03:11:25 -0800 Subject: [PATCH 207/440] Call mem callbacks with addr, value --- .../Classes/Api/MemEventsApi.cs | 8 +++--- .../Interfaces/Api/IMemEvents.cs | 24 ++++++++--------- .../lua/EmuLuaLibrary.Events.cs | 6 ++--- BizHawk.Client.Common/lua/LuaFunctionList.cs | 4 +-- BizHawk.Client.Common/lua/NamedLuaFunction.cs | 7 +++++ .../tools/Debugger/Breakpoint.cs | 10 +++---- .../tools/Debugger/BreakpointControl.cs | 6 ++--- .../CallbackBasedTraceBuffer.cs | 6 ++--- .../MemoryCallbackSystem.cs | 26 +++++++++---------- .../Interfaces/IMemoryCallbackSystem.cs | 12 ++++----- .../CPUs/CP1610/CP1610.Execute.cs | 2 +- BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs | 4 +-- .../CPUs/HuC6280/Execute.cs | 2 +- .../CPUs/HuC6280/HuC6280.cs | 4 +-- .../Computers/AppleII/AppleII.cs | 6 ++--- .../Consoles/Atari/2600/Atari2600.Core.cs | 6 ++--- .../Consoles/Atari/A7800Hawk/A7800Hawk.cs | 2 +- .../Consoles/Atari/A7800Hawk/MemoryMap.cs | 4 +-- .../Consoles/Nintendo/GBA/VBANext.cs | 6 ++--- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 2 +- .../Consoles/Nintendo/GBHawk/MemoryMap.cs | 4 +-- .../Nintendo/GBHawkLink/GBHawkLink.cs | 2 +- .../Nintendo/Gameboy/Gambatte.IDebuggable.cs | 6 ++--- .../N64/NativeApi/mupen64plusCoreApi.cs | 6 ++--- .../Consoles/Nintendo/NES/NES.Core.cs | 6 ++--- .../Consoles/Nintendo/SNES/LibsnesCore.cs | 12 ++++----- .../Nintendo/SubNESHawk/SubNESHawk.cs | 2 +- .../Consoles/Sega/SMS/SMS.cs | 6 ++--- .../Consoles/Sega/gpgx64/GPGX.IDebuggable.cs | 6 ++--- .../Consoles/Sega/gpgx64/GPGX.ITraceable.cs | 2 +- .../Consoles/Sony/PSX/Octoshock.cs | 6 ++--- .../Consoles/WonderSwan/WonderSwan.cs | 6 ++--- 32 files changed, 109 insertions(+), 102 deletions(-) diff --git a/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs b/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs index 5848df5fc3..8db4c5223f 100644 --- a/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs +++ b/BizHawk.Client.ApiHawk/Classes/Api/MemEventsApi.cs @@ -13,28 +13,28 @@ namespace BizHawk.Client.ApiHawk public MemEventsApi () : base() { } - public void AddReadCallback(Action cb, uint address, string domain) + public void AddReadCallback(Action cb, uint? address, string domain) { if (DebuggableCore.MemoryCallbacksAvailable()) { DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Read, "Plugin Hook", cb, address, null)); } } - public void AddWriteCallback(Action cb, uint address, string domain) + public void AddWriteCallback(Action cb, uint? address, string domain) { if (DebuggableCore.MemoryCallbacksAvailable()) { DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Write, "Plugin Hook", cb, address, null)); } } - public void AddExecCallback(Action cb, uint address, string domain) + public void AddExecCallback(Action cb, uint? address, string domain) { if (DebuggableCore.MemoryCallbacksAvailable() && DebuggableCore.MemoryCallbacks.ExecuteCallbacksAvailable) { DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Execute, "Plugin Hook", cb, address, null)); } } - public void RemoveMemoryCallback(Action cb) + public void RemoveMemoryCallback(Action cb) { if (DebuggableCore.MemoryCallbacksAvailable()) { diff --git a/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs index b8650a9139..2b497ea11c 100644 --- a/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs +++ b/BizHawk.Client.ApiHawk/Interfaces/Api/IMemEvents.cs @@ -1,12 +1,12 @@ -using System; - -namespace BizHawk.Client.ApiHawk -{ - public interface IMemEvents : IExternalApi - { - void AddReadCallback(Action cb, uint address, string domain); - void AddWriteCallback(Action cb, uint address, string domain); - void AddExecCallback(Action cb, uint address, string domain); - void RemoveMemoryCallback(Action cb); - } -} +using System; + +namespace BizHawk.Client.ApiHawk +{ + public interface IMemEvents : IExternalApi + { + void AddReadCallback(Action cb, uint? address, string domain); + void AddWriteCallback(Action cb, uint? address, string domain); + void AddExecCallback(Action cb, uint? address, string domain); + void RemoveMemoryCallback(Action cb); + } +} diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs index f8d94f10e8..594ae78d2e 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs @@ -243,7 +243,7 @@ namespace BizHawk.Client.Common } DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(domain, MemoryCallbackType.Execute, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Execute, "Lua Hook", nlf.MemCallback, address, null)); return nlf.Guid.ToString(); } } @@ -282,7 +282,7 @@ namespace BizHawk.Client.Common } DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(domain, MemoryCallbackType.Read, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Read, "Lua Hook", nlf.MemCallback, address, null)); return nlf.Guid.ToString(); } } @@ -321,7 +321,7 @@ namespace BizHawk.Client.Common } DebuggableCore.MemoryCallbacks.Add( - new MemoryCallback(domain, MemoryCallbackType.Write, "Lua Hook", nlf.Callback, address, null)); + new MemoryCallback(domain, MemoryCallbackType.Write, "Lua Hook", nlf.MemCallback, address, null)); return nlf.Guid.ToString(); } } diff --git a/BizHawk.Client.Common/lua/LuaFunctionList.cs b/BizHawk.Client.Common/lua/LuaFunctionList.cs index 45ec368722..87d36e9d3b 100644 --- a/BizHawk.Client.Common/lua/LuaFunctionList.cs +++ b/BizHawk.Client.Common/lua/LuaFunctionList.cs @@ -24,7 +24,7 @@ namespace BizHawk.Client.Common if (Global.Emulator.MemoryCallbacksAvailable()) { - Global.Emulator.AsDebuggable().MemoryCallbacks.Remove(function.Callback); + Global.Emulator.AsDebuggable().MemoryCallbacks.Remove(function.MemCallback); } return base.Remove(function); @@ -40,7 +40,7 @@ namespace BizHawk.Client.Common if (Global.Emulator.MemoryCallbacksAvailable()) { var memoryCallbacks = Global.Emulator.AsDebuggable().MemoryCallbacks; - memoryCallbacks.RemoveAll(this.Select(w => w.Callback)); + memoryCallbacks.RemoveAll(this.Select(w => w.MemCallback)); } Clear(); diff --git a/BizHawk.Client.Common/lua/NamedLuaFunction.cs b/BizHawk.Client.Common/lua/NamedLuaFunction.cs index d10d2eb0b3..2bdb677ed9 100644 --- a/BizHawk.Client.Common/lua/NamedLuaFunction.cs +++ b/BizHawk.Client.Common/lua/NamedLuaFunction.cs @@ -30,6 +30,11 @@ namespace BizHawk.Client.Common ex.Message); } }; + + MemCallback = delegate + { + Callback(); + }; } public Guid Guid { get; private set; } @@ -42,6 +47,8 @@ namespace BizHawk.Client.Common public Action Callback { get; } + public Action MemCallback { get; } + public void Call(string name = null) { LuaSandbox.Sandbox(Lua, () => diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs index 3f4aca4106..3d9ea3b08b 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/Breakpoint.cs @@ -7,7 +7,7 @@ namespace BizHawk.Client.EmuHawk { public class BreakpointList : List { - public Action Callback { get; set; } + public Action Callback { get; set; } public void Add(IDebuggable core, string scope, uint address, uint mask, MemoryCallbackType type) { @@ -69,7 +69,7 @@ namespace BizHawk.Client.EmuHawk private bool _active; private readonly IDebuggable _core; - public Breakpoint(bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { Scope = scope; _core = core; @@ -83,7 +83,7 @@ namespace BizHawk.Client.EmuHawk ReadOnly = readOnly; } - public Breakpoint(IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { Scope = scope; _core = core; @@ -96,7 +96,7 @@ namespace BizHawk.Client.EmuHawk Active = enabled; } - public Breakpoint(string name, bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) + public Breakpoint(string name, bool readOnly, IDebuggable core, string scope, Action callBack, uint address, uint mask, MemoryCallbackType type, bool enabled = true) { Scope = scope; _core = core; @@ -111,7 +111,7 @@ namespace BizHawk.Client.EmuHawk } public string Scope { get; } - public Action Callback { get; } + public Action Callback { get; } public uint? Address { get; set; } public uint? AddressMask { get; set; } public MemoryCallbackType Type { get; set; } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs index 17428ebc77..2224cb3e56 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs @@ -60,16 +60,16 @@ namespace BizHawk.Client.EmuHawk : Color.White; } - private void BreakpointCallback() + private void BreakpointCallback(uint addr, uint value) { GlobalWin.MainForm.PauseEmulator(); UpdateValues(); GlobalWin.OSD.AddMessage("Breakpoint hit"); } - private void SeekCallback() + private void SeekCallback(uint addr, uint value) { - BreakpointCallback(); + BreakpointCallback(addr, value); var seekBreakpoint = _breakpoints.FirstOrDefault(x => x.Name.StartsWith(SeekName)); diff --git a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs index 4a93abc213..b37479fd36 100644 --- a/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs +++ b/BizHawk.Emulation.Common/Base Implementations/CallbackBasedTraceBuffer.cs @@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Common protected readonly List Buffer = new List(); - protected abstract void TraceFromCallback(); + protected abstract void TraceFromCallback(uint addr, uint value); private ITraceSink _sink; @@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Common public class TracingMemoryCallback : IMemoryCallback { - public TracingMemoryCallback(Action callback) + public TracingMemoryCallback(Action callback) { Callback = callback; } @@ -89,7 +89,7 @@ namespace BizHawk.Emulation.Common public string Name => "Trace Logging"; - public Action Callback { get; } + public Action Callback { get; } public uint? Address => null; diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs index 0df3232a4a..24edf2dde6 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs @@ -67,38 +67,38 @@ namespace BizHawk.Emulation.Common } } - private static void Call(ObservableCollection cbs, uint addr, string scope) + private static void Call(ObservableCollection cbs, uint addr, uint value, string scope) { for (int i = 0; i < cbs.Count; i++) { if (!cbs[i].Address.HasValue || (cbs[i].Scope == scope && cbs[i].Address == (addr & cbs[i].AddressMask))) { - cbs[i].Callback(); + cbs[i].Callback(addr, 0); } } } - public void CallReads(uint addr, string scope) + public void CallReads(uint addr, uint value, string scope) { if (_hasReads) { - Call(_reads, addr, scope); + Call(_reads, addr, value, scope); } } - public void CallWrites(uint addr, string scope) + public void CallWrites(uint addr, uint value, string scope) { if (_hasWrites) { - Call(_writes, addr, scope); + Call(_writes, addr, value, scope); } } - public void CallExecutes(uint addr, string scope) + public void CallExecutes(uint addr, uint value, string scope) { if (_hasExecutes) { - Call(_execs, addr, scope); + Call(_execs, addr, value, scope); } } @@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Common return (_hasReads != hadReads || _hasWrites != hadWrites || _hasExecutes != hadExecutes); } - private int RemoveInternal(Action action) + private int RemoveInternal(Action action) { var readsToRemove = _reads.Where(imc => imc.Callback == action).ToList(); var writesToRemove = _writes.Where(imc => imc.Callback == action).ToList(); @@ -160,7 +160,7 @@ namespace BizHawk.Emulation.Common return readsToRemove.Count + writesToRemove.Count + execsToRemove.Count; } - public void Remove(Action action) + public void Remove(Action action) { if (RemoveInternal(action) > 0) { @@ -171,7 +171,7 @@ namespace BizHawk.Emulation.Common } } - public void RemoveAll(IEnumerable actions) + public void RemoveAll(IEnumerable> actions) { bool changed = false; foreach (var action in actions) @@ -286,7 +286,7 @@ namespace BizHawk.Emulation.Common public class MemoryCallback : IMemoryCallback { - public MemoryCallback(string scope, MemoryCallbackType type, string name, Action callback, uint? address, uint? mask) + public MemoryCallback(string scope, MemoryCallbackType type, string name, Action callback, uint? address, uint? mask) { if (type == MemoryCallbackType.Execute && !address.HasValue) { @@ -303,7 +303,7 @@ namespace BizHawk.Emulation.Common public MemoryCallbackType Type { get; } public string Name { get; } - public Action Callback { get; } + public Action Callback { get; } public uint? Address { get; } public uint? AddressMask { get; } public string Scope { get; } diff --git a/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs index f87a8e492d..24cee31137 100644 --- a/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Interfaces/IMemoryCallbackSystem.cs @@ -65,31 +65,31 @@ namespace BizHawk.Emulation.Common /// /// The address to check for callbacks /// The scope that the address pertains to. Must be a value in - void CallReads(uint addr, string scope); + void CallReads(uint addr, uint value, string scope); /// /// Executes all Write callbacks for the given address and domain /// /// The address to check for callbacks /// The scope that the address pertains to. Must be a value in - void CallWrites(uint addr, string scope); + void CallWrites(uint addr, uint value, string scope); /// /// Executes all Execute callbacks for the given address and domain /// /// The address to check for callbacks /// The scope that the address pertains to. Must be a value in - void CallExecutes(uint addr, string scope); + void CallExecutes(uint addr, uint value, string scope); /// /// Removes the given callback from the list /// - void Remove(Action action); + void Remove(Action action); /// /// Removes the given callbacks from the list /// - void RemoveAll(IEnumerable actions); + void RemoveAll(IEnumerable> actions); ///
/// Removes all read,write, and execute callbacks @@ -111,7 +111,7 @@ namespace BizHawk.Emulation.Common { MemoryCallbackType Type { get; } string Name { get; } - Action Callback { get; } + Action Callback { get; } uint? Address { get; } uint? AddressMask { get; } string Scope { get; } diff --git a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs index c30c140bff..8d36295e3f 100644 --- a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.Execute.cs @@ -192,7 +192,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 if (MemoryCallbacks != null) { - MemoryCallbacks.CallExecutes(RegisterPC, "System Bus"); + MemoryCallbacks.CallExecutes(RegisterPC, 0, "System Bus"); } switch (opcode) diff --git a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs index 8a4ced6fa0..5f6c87ef66 100644 --- a/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs +++ b/BizHawk.Emulation.Cores/CPUs/CP1610/CP1610.cs @@ -31,7 +31,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 { if (MemoryCallbacks != null && !peek) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); } return ReadMemory(addr, peek); @@ -41,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Components.CP1610 { if (MemoryCallbacks != null && !poke) { - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); } WriteMemory(addr, value, poke); diff --git a/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs b/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs index e86edcc297..09328c92df 100644 --- a/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/HuC6280/Execute.cs @@ -60,7 +60,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 LagIFlag = FlagI; if (Debug) Logger(State()); - MemoryCallbacks.CallExecutes(PC, "System Bus"); + MemoryCallbacks.CallExecutes(PC, 0, "System Bus"); if (CDL != null && CDL.Active) CDLOpcode(); diff --git a/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs b/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs index 9e2e8ad470..6f95f789ae 100644 --- a/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs +++ b/BizHawk.Emulation.Cores/CPUs/HuC6280/HuC6280.cs @@ -230,7 +230,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 { byte page = MPR[address >> 13]; var result = ReadMemory21((page << 13) | (address & 0x1FFF)); - MemoryCallbacks.CallReads(address, "System Bus"); + MemoryCallbacks.CallReads(address, result, "System Bus"); return result; } @@ -238,7 +238,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280 { byte page = MPR[address >> 13]; WriteMemory21((page << 13) | (address & 0x1FFF), value); - MemoryCallbacks.CallWrites(address, "System Bus"); + MemoryCallbacks.CallWrites(address, value, "System Bus"); } private ushort ReadWord(ushort address) diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs index e67abf06ef..9d35c23ea2 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs @@ -183,9 +183,9 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII private void SetCallbacks() { - _machine.Memory.ReadCallback = (addr) => MemoryCallbacks.CallReads(addr, "System Bus"); - _machine.Memory.WriteCallback = (addr) => MemoryCallbacks.CallWrites(addr, "System Bus"); - _machine.Memory.ExecuteCallback = (addr) => MemoryCallbacks.CallExecutes(addr, "System Bus"); + _machine.Memory.ReadCallback = (addr) => MemoryCallbacks.CallReads(addr, 0, "System Bus"); + _machine.Memory.WriteCallback = (addr) => MemoryCallbacks.CallWrites(addr, 0, "System Bus"); + _machine.Memory.ExecuteCallback = (addr) => MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); _machine.Memory.InputCallback = InputCallbacks.Call; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index 4d9bb84286..199a2ea393 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -160,7 +160,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _mapper.Bit13 = addr.Bit(13); var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF)); _tia.BusState = temp; - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); return temp; } @@ -181,7 +181,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _mapper.WriteMemory((ushort)(addr & 0x1FFF), value); - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); } internal void PokeMemory(ushort addr, byte value) @@ -191,7 +191,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } private void RebootCore() diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs index 7d64189dca..cdf8024739 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs @@ -291,7 +291,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } private void Reset_Mapper(string m) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs index 6f3e76aba5..fc8108ce99 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs @@ -20,7 +20,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { public byte ReadMemory(ushort addr) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); if ((addr & 0xFCE0) == 0) { @@ -98,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public void WriteMemory(ushort addr, byte value) { - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); if ((addr & 0xFCE0) == 0) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index 247d7fd68d..3e9493c92b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -168,9 +168,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA void InitCallbacks() { padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call()); - fetchcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallExecutes(addr, "System Bus")); - readcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallReads(addr, "System Bus")); - writecb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallWrites(addr, "System Bus")); + fetchcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallExecutes(addr, 0, "System Bus")); + readcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallReads(addr, 0, "System Bus")); + writecb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallWrites(addr, 0, "System Bus")); tracecb = new LibVBANext.TraceCallback((addr, opcode) => Tracer.Put(Trace(addr, opcode))); _inputCallbacks.ActiveChanged += SyncPadCallback; _memorycallbacks.ActiveChanged += SyncMemoryCallbacks; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 00e89a039e..efe4d40e05 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -296,7 +296,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } private void Setup_Mapper() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs index fdeafdc9e3..fa546bb745 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs @@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { public byte ReadMemory(ushort addr) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); addr_access = addr; if (ppu.DMA_start) @@ -157,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public void WriteMemory(ushort addr, byte value) { - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); addr_access = addr; if (ppu.DMA_start) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index 619a17c479..6b6382d4b6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -96,7 +96,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs index 075ee71d27..1006903e43 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IDebuggable.cs @@ -59,19 +59,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy private void ReadCallback(uint address, ulong cycleOffset) { callbackCycleCount = _cycleCount + cycleOffset; - MemoryCallbacks.CallReads(address, "System Bus"); + MemoryCallbacks.CallReads(address, 0, "System Bus"); } private void WriteCallback(uint address, ulong cycleOffset) { callbackCycleCount = _cycleCount + cycleOffset; - MemoryCallbacks.CallWrites(address, "System Bus"); + MemoryCallbacks.CallWrites(address, 0, "System Bus"); } private void ExecCallback(uint address, ulong cycleOffset) { callbackCycleCount = _cycleCount + cycleOffset; - MemoryCallbacks.CallExecutes(address, "System Bus"); + MemoryCallbacks.CallExecutes(address, 0, "System Bus"); } /// diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index c499855ae5..1f89a92ece 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -755,13 +755,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi switch (_breakparams._type) { case BreakType.Read: - _breakparams._mcs.CallReads(_breakparams._addr, "System Bus"); + _breakparams._mcs.CallReads(_breakparams._addr, 0, "System Bus"); break; case BreakType.Write: - _breakparams._mcs.CallWrites(_breakparams._addr, "System Bus"); + _breakparams._mcs.CallWrites(_breakparams._addr, 0, "System Bus"); break; case BreakType.Execute: - _breakparams._mcs.CallExecutes(_breakparams._addr, "System Bus"); + _breakparams._mcs.CallExecutes(_breakparams._addr, 0, "System Bus"); break; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index ac9f0d3b26..72fa925abd 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -916,7 +916,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } public byte ReadMemory(ushort addr) @@ -966,7 +966,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, ret, "System Bus"); DB = ret; return ret; @@ -1013,7 +1013,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES Board.WritePRG(addr - 0x8000, value); } - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); } // the palette for each VS game needs to be chosen explicitly since there are 6 different ones. diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs index 94e6335b79..dbd655cc9a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -364,7 +364,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void ReadHook(uint addr) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); @@ -372,7 +372,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void ExecHook(uint addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); @@ -380,7 +380,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void WriteHook(uint addr, byte val) { - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, val, "System Bus"); // we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point // EDIT: for now, theres some IPC re-entrancy problem // RefreshMemoryCallbacks(); @@ -388,17 +388,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES private void ReadHook_SMP(uint addr) { - MemoryCallbacks.CallReads(addr, "SMP"); + MemoryCallbacks.CallReads(addr, 0, "SMP"); } private void ExecHook_SMP(uint addr) { - MemoryCallbacks.CallExecutes(addr, "SMP"); + MemoryCallbacks.CallExecutes(addr, 0, "SMP"); } private void WriteHook_SMP(uint addr, byte val) { - MemoryCallbacks.CallWrites(addr, "SMP"); + MemoryCallbacks.CallWrites(addr, val, "SMP"); } private enum LoadParamType diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs index bc20055601..6ae3dc1d52 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SubNESHawk/SubNESHawk.cs @@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk private void ExecFetch(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } #region ISettable diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs index bba177d817..5430c859de 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs @@ -283,7 +283,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem private byte ReadMemory(ushort addr) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); return ReadMemoryMapper(addr); } @@ -292,7 +292,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { WriteMemoryMapper(addr, value); - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, value, "System Bus"); } private byte FetchMemory(ushort addr) @@ -302,7 +302,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem private void OnExecMemory(ushort addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } /// diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs index 9b5e7363d9..dd895b4cb4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IDebuggable.cs @@ -61,9 +61,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx private void InitMemCallbacks() { - ExecCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallExecutes(a, "M68K BUS")); - ReadCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallReads(a, "M68K BUS")); - WriteCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallWrites(a, "M68K BUS")); + ExecCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallExecutes(a, 0, "M68K BUS")); + ReadCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallReads(a, 0, "M68K BUS")); + WriteCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallWrites(a, 0, "M68K BUS")); _memoryCallbacks.ActiveChanged += RefreshMemCallbacks; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs index c8d8dab662..7c6717e04c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx Header = "M68K: PC, machine code, mnemonic, operands, registers (D0-D7, A0-A7, SR, USP), flags (XNZVC)"; } - protected override void TraceFromCallback() + protected override void TraceFromCallback(uint addr, uint value) { var regs = DebuggableCore.GetCpuFlagsAndRegisters(); uint pc = (uint)regs["M68K PC"].Value; diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index eca318a577..06f3145933 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -883,13 +883,13 @@ namespace BizHawk.Emulation.Cores.Sony.PSX switch (type) { case OctoshockDll.eShockMemCb.Read: - MemoryCallbacks.CallReads(address, "System Bus"); + MemoryCallbacks.CallReads(address, value, "System Bus"); break; case OctoshockDll.eShockMemCb.Write: - MemoryCallbacks.CallWrites(address, "System Bus"); + MemoryCallbacks.CallWrites(address, value, "System Bus"); break; case OctoshockDll.eShockMemCb.Execute: - MemoryCallbacks.CallExecutes(address, "System Bus"); + MemoryCallbacks.CallExecutes(address, value, "System Bus"); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index b5224065ea..5fcb14f2a8 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -142,15 +142,15 @@ namespace BizHawk.Emulation.Cores.WonderSwan void ReadCallback(uint addr) { - MemoryCallbacks.CallReads(addr, "System Bus"); + MemoryCallbacks.CallReads(addr, 0, "System Bus"); } void WriteCallback(uint addr) { - MemoryCallbacks.CallWrites(addr, "System Bus"); + MemoryCallbacks.CallWrites(addr, 0, "System Bus"); } void ExecCallback(uint addr) { - MemoryCallbacks.CallExecutes(addr, "System Bus"); + MemoryCallbacks.CallExecutes(addr, 0, "System Bus"); } void ButtonCallback() { From fe3455be7d8189192e17350e4f2bdd73aa02906e Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Thu, 24 Jan 2019 03:25:50 -0800 Subject: [PATCH 208/440] call with value, not 0 --- .../Base Implementations/MemoryCallbackSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs index 24edf2dde6..794986c830 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs @@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Common { if (!cbs[i].Address.HasValue || (cbs[i].Scope == scope && cbs[i].Address == (addr & cbs[i].AddressMask))) { - cbs[i].Callback(addr, 0); + cbs[i].Callback(addr, value); } } } From 1d6bd43532f5680c0b2f9382536eef6a38e96987 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 21:57:04 +1000 Subject: [PATCH 209/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f71078672..11d64e2e7c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -[![unique systems emulated | 27](https://img.shields.io/badge/unique_systems_emulated-27-darkgreen.svg?logo=buffer&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 27](https://img.shields.io/badge/unique_systems_emulated-27-darkgreen.svg?logo=data:image/png;base64,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&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) From 41f464b80cc58e515928187f20800072d3a40a9b Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:09:31 +1000 Subject: [PATCH 210/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11d64e2e7c..e8979316e3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c Click the "release" button above to grab the latest stable version ([changelog at TASVideos](http://tasvideos.org/Bizhawk/ReleaseHistory.html)). -New user on Windows? Install the prerequisites first, click the "prereqs" button to get that and see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) for info. +New user on Windows? Install the prerequisites first, click the "prereqs" button to get that and see [*Installing*](#windows-78110) for info. **Never mix different versions** of BizHawk — Keep each version in its own folder. From 73366ef5afbe88cd44e9c25c36aa56ddb6a34869 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:17:21 +1000 Subject: [PATCH 211/440] Update README.md --- README.md | 60 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e8979316e3..0210d637d9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for casual players, it also has recording/playback and debugging tools, making it the first choice for TASers (Tool-Assisted Speedrunners). -[![unique systems emulated | 27](https://img.shields.io/badge/unique_systems_emulated-27-darkgreen.svg?logo=data:image/png;base64,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&style=popout)](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) +[![unique systems emulated | 27](https://img.shields.io/badge/unique_systems_emulated-27-darkgreen.svg?logo=data:image/png;base64,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&style=popout)](#cores) [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) @@ -17,19 +17,19 @@ New user on Windows? Install the prerequisites first, click the "prereqs" button Jump to: * Installing - * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110) - * [GNU+Linux](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux) + * [Windows 7/8.1/10](#windows-78110) + * [GNU+Linux](#gnulinux) * Building - * [Windows 7/8.1/10](https://github.com/TASVideos/BizHawk/blob/master/README.md#windows-78110-1) - * [GNU+Linux](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) -* [Usage](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) - * [TASing](https://github.com/TASVideos/BizHawk/blob/master/README.md#tasing) - * [Testing](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) - * [Cores](https://github.com/TASVideos/BizHawk/blob/master/README.md#cores) -* [Support and troubleshooting](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) -* [Contributing](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) -* [Related projects](https://github.com/TASVideos/BizHawk/blob/master/README.md#related-projects) -* [License](https://github.com/TASVideos/BizHawk/blob/master/README.md#license) + * [Windows 7/8.1/10](#windows-78110-1) + * [GNU+Linux](#gnulinux-1) +* [Usage](#usage) + * [TASing](#tasing) + * [Testing](#testing) + * [Cores](#cores) +* [Support and troubleshooting](#support-and-troubleshooting) +* [Contributing](#contributing) +* [Related projects](#related-projects) +* [License](#license) ## Features and systems @@ -81,9 +81,9 @@ Supported consoles and computers: * Uzebox * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? -See [*Usage*](https://github.com/TASVideos/BizHawk/blob/master/README.md#usage) below for details about specific tools and config menus. +See [*Usage*](#usage) below for details about specific tools and config menus. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Installing @@ -109,7 +109,7 @@ Following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/he A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for Windows XP and 32-bit users. Being in the 1.x series, many bugs remain and features are missing. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ### GNU+Linux @@ -117,7 +117,7 @@ A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag **IMPORTANT**: Linux support is a work-in-progress! It is *not* complete, does *not* look very nice, and is *not* ready for anything that needs accuracy. -You'll need to either build BizHawk yourself (see [*Building*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux-1) below), or download a dev build (see [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) below). +You'll need to either build BizHawk yourself (see [*Building*](#gnulinux-1) below), or download a dev build (see [*Testing*](#testing) below). The runtime dependencies are Mono (complete) + Mono VB.NET, WINE (just `libwine` if available), `libdl.so` (glibc), NVIDIA's `cgc` utility, and `libblip_buf.so` from the repo's `Assets` folder (copy it to `/usr/lib/libblip_buf.so.1.1.0` or equivalent). LSB release info is optional for automatically setting the library location. @@ -125,7 +125,7 @@ Run `EmuHawkMono.sh` to give Mono the library and executable paths — you can r The systems that currently work are: GB + GBC (GBHawk), NES (NesHawk), SMS, Atari 7800, and some classic home computers. See [#1430](https://github.com/TASVideos/BizHawk/issues/1430) for progress. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Building @@ -142,7 +142,7 @@ Once it's downloaded and extracted, go into the repo's `Dist` folder and run `Bu For anything more complicated than building, you'll need an IDE like [VS Community 2017](https://visualstudio.microsoft.com/vs/community), currently the best free C# IDE. Open `BizHawk.sln` with VS to start and use the toolbar to choose EmuHawk and build. See [Compiling at TASVideos](http://tasvideos.org/Bizhawk/Compiling.html) (somewhat outdated) for more detailed instructions. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ### GNU+Linux @@ -161,11 +161,11 @@ Remove the `/p:...` flag from MSBuild if you want debugging symbols. If your distro isn't listed under *Installing* above, `libblip_buf` probably isn't in your package repos. You can easily [build it yourself](https://gitlab.com/TASVideos/libblip_buf/blob/unified/README.md). -Once built, see [*Installing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#gnulinux) above, substituting the repo's `output` folder for the download. +Once built, see [*Installing*](#gnulinux) above, substituting the repo's `output` folder for the download. Again, if your distro isn't listed there, you might get an "Unknown distro" warning in the terminal, and BizHawk may not open or may show the missing dependencies dialog. You may need to add your distro to the case statement in the script, setting `libpath` to the location of `d3dx9_43.dll.so` (please do share if you get it working). -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Usage @@ -208,7 +208,7 @@ Running scripts have a "▶️" beside their name, and stopped scripts (manually "Toggle script" does just that (paused scripts are stopped). "Reload script" stops it and loads changes to the file, running scripts are then started again. "Remove script" stops it and removes it from the list. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ### TASing @@ -216,17 +216,17 @@ Running scripts have a "▶️" beside their name, and stopped scripts (manually For now, the best way to learn how to TAS is to browse pages like [BasicTools](http://tasvideos.org/TasingGuide/BasicTools.html) on TASVideos and watch tutorials like [Sand_Knight and dwangoAC's](https://youtu.be/6tJniMaR2Ps). -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ### Testing -Testing bugfixes or new features can be just as helpful as making them! If code's more your thing, see [*Contributing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#contributing) below. +Testing bugfixes or new features can be just as helpful as making them! If code's more your thing, see [*Contributing*](#contributing) below. Dev builds are automated with AppVeyor, every green checkmark in the [commit history](https://github.com/TASVideos/BizHawk/commits/master) is a successful build. Clicking a checkmark and then "Details" in the box that appears takes you straight to the build page. The full list is [here](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history), in future use the "dev builds" button at the top of this readme. Once you're on the build page, click "Artifacts" and download `BizHawk_Developer--#.zip`. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ### Cores @@ -264,7 +264,7 @@ ZX Spectrum | ZXHawk | Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see below). -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Support and troubleshooting @@ -276,19 +276,19 @@ A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Contributing BizHawk is Open Source Software, so you're free to modify it however you please, and if you do, we invite you to share! Under the permissive *MIT License*, this is optional, just be careful with reusing cores as some have copyleft licenses. -Not a programmer? Something as simple as reproducing bugs with different software versions is still very helpful! See [*Testing*](https://github.com/TASVideos/BizHawk/blob/master/README.md#testing) above to learn about dev builds if you'd rather help us get the next release out. +Not a programmer? Something as simple as reproducing bugs with different software versions is still very helpful! See [*Testing*](#testing) above to learn about dev builds if you'd rather help us get the next release out. If you'd like to fix bugs, check the issue tracker here on GitHub: [![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) -It's a good idea to check if anyone is already working on an issue by asking on IRC (see [*Support*](https://github.com/TASVideos/BizHawk/blob/master/README.md#support-and-troubleshooting) above). +It's a good idea to check if anyone is already working on an issue by asking on IRC (see [*Support*](#support-and-troubleshooting) above). If you'd like to add a feature, first search the issue tracker for it. If it's a new idea, make your own feature request issue before you start coding. @@ -296,7 +296,7 @@ For the time being, style is not enforced in PRs, only build success is. Please Past contrbutors to the frontend and custom-built cores are listed [here](https://github.com/TASVideos/BizHawk/graphs/contributors). See the wiki for core authors. -[to top](https://github.com/TASVideos/BizHawk/blob/master/README.md#bizhawk) +[to top](#bizhawk) ## Related projects From 4f3dc6dafcfd89dfe2508f800ea127fe4e59d42d Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:25:48 +1000 Subject: [PATCH 212/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0210d637d9..aa2c0cb4a9 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ Past contrbutors to the frontend and custom-built cores are listed [here](https: * [DeSmuME](https://desmume.org) for DS/Lite — cross-platform * [Dolphin](https://dolphin-emu.org) for GameCube and (original) Wii — cross-platform -* [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run on Unix +* [FCEUX](http://www.fceux.com/web/home.html) for NES/Famicom — TASing is Windows-only, but it should run cross-platform * [libTAS](https://github.com/clementgallet/libTAS) for Linux ELF — GNU+Linux-only, also emulates other emulators * [lsnes](http://tasvideos.org/Lsnes.html) for GB and SNES — cross-platform * [openMSX](https://openmsx.org) for MSX — cross-platform From 50e5978144594267385f0f211eb97e4590ce0a60 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:27:11 +1000 Subject: [PATCH 213/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa2c0cb4a9..a76982b3cc 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Supported consoles and computers: * Uzebox * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? -See [*Usage*](#usage) below for details about specific tools and config menus. +See [*Usage*](#usage) below for an introduction to basic config menus. [to top](#bizhawk) From ca42daa157654ea2d000d177c99d8d264c3af052 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:31:36 +1000 Subject: [PATCH 214/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a76982b3cc..d614ee5ec4 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Supported consoles and computers: * Uzebox * [More](http://tasvideos.org/Bizhawk/CoreRoadMap.html) coming soon..? -See [*Usage*](#usage) below for an introduction to basic config menus. +See [*Usage*](#usage) below for info on basic config needed to play games. [to top](#bizhawk) @@ -107,7 +107,7 @@ BizHawk functions like a "portable" program, you may move or rename the folder c Following [Microsoft's support lifecycle](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet), Win10 is supported from 1709 "Redstone 3", Win8 is supported from 8.1, and Win7 is supported from SP1 (ends Jan 2020, upgrade to Win10 or try [ReactOS](https://reactos.org/joining/faqs)). -A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for Windows XP and 32-bit users. Being in the 1.x series, many bugs remain and features are missing. +A "backport" release, [1.13.2](https://github.com/TASVideos/BizHawk/releases/tag/1.13.2), is available for users of Windows XP and/or 32-bit Windows. Being in the 1.x series, many bugs remain and features are missing. [to top](#bizhawk) From 363166fa909aa093251c5196e4f305b6f06755b5 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:32:50 +1000 Subject: [PATCH 215/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d614ee5ec4..ce68dc1a22 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ Virtual Boy | Virtual Boyee | WonderSwan / Color | Cygne | ZX Spectrum | ZXHawk | -Amstrad CPC, Magnavox Odyssey², and PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see below). +Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress and there is **no ETA**. Cores for other systems are only conceptual. If you want to help speed up development, ask on IRC (see below). [to top](#bizhawk) From 530790b5152c0061322d6c92b4b37c1733f83d22 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:35:41 +1000 Subject: [PATCH 216/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce68dc1a22..31ca56affb 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: -[![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat)](ircs://chat.freenode.net:6697/bizhawk) +![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat) [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) From 68575853846950ff5db32bb8c1e743c4c7fb4932 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:38:42 +1000 Subject: [PATCH 217/440] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 31ca56affb..4be281cc24 100644 --- a/README.md +++ b/README.md @@ -268,9 +268,8 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an ## Support and troubleshooting -A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC. Paste `ircs://chat.freenode.net:6697/bizhawk` into your address bar, connect to freenode manually with your IRC client and join `#bizhawk`, or try these: -![IRC | chat.freenode.net #bizhawk](https://img.shields.io/badge/IRC-chat.freenode.net_%23bizhawk-steelblue.svg?style=flat) [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) From 659c80a7409d78cadb5664e8deb69a6e6c15e1e3 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:39:40 +1000 Subject: [PATCH 218/440] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4be281cc24..afb8ef56b0 100644 --- a/README.md +++ b/README.md @@ -268,10 +268,11 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an ## Support and troubleshooting -A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC. Paste `ircs://chat.freenode.net:6697/bizhawk` into your address bar, connect to freenode manually with your IRC client and join `#bizhawk`, or try these: - -[![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -[![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: +* `ircs://chat.freenode.net:6697/bizhawk` +* connect to freenode manually with your IRC client and join `#bizhawk` +* [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +* [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From 24e3e46620aada30cd9edf731c2feb7dc5f93cfa Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:42:13 +1000 Subject: [PATCH 219/440] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index afb8ef56b0..32a6781a18 100644 --- a/README.md +++ b/README.md @@ -271,8 +271,8 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: * `ircs://chat.freenode.net:6697/bizhawk` * connect to freenode manually with your IRC client and join `#bizhawk` -* [![Matrix (IRC bridge) | #freenode_#bizhawk:matrix.org](https://img.shields.io/badge/Matrix_(IRC_bridge)-%23freenode__%23bizhawk:matrix.org-mediumpurple.svg?logo=matrix&style=flat)](https://matrix.to/#/#freenode_#bizhawk:matrix.org) -* [![freenode webchat | #bizhawk](https://img.shields.io/badge/freenode_webchat-%23bizhawk-lightcoral.svg?style=flat)](http://webchat.freenode.net/?channels=bizhawk) +* connect with a Matrix client (via matrix.org's IRC bridge): [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +* use freenode's [*webchat*](http://webchat.freenode.net/?channels=bizhawk), an IRC client in a webpage If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From 7266cef5aab2d00b0b39555af6836d20ddc9ac9d Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:44:02 +1000 Subject: [PATCH 220/440] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32a6781a18..56f0652ccb 100644 --- a/README.md +++ b/README.md @@ -269,9 +269,8 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an ## Support and troubleshooting A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: -* `ircs://chat.freenode.net:6697/bizhawk` -* connect to freenode manually with your IRC client and join `#bizhawk` -* connect with a Matrix client (via matrix.org's IRC bridge): [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) +* with an IRC client, join channel `#bizhawk` on `chat.freenode.net:6697` +* connect to [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) with a Matrix client (via matrix.org's IRC bridge) * use freenode's [*webchat*](http://webchat.freenode.net/?channels=bizhawk), an IRC client in a webpage If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From 81920d0dee90bcba059ab16acdc75d5c6a8afec6 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:48:19 +1000 Subject: [PATCH 221/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56f0652ccb..12121e3b0b 100644 --- a/README.md +++ b/README.md @@ -271,7 +271,7 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: * with an IRC client, join channel `#bizhawk` on `chat.freenode.net:6697` * connect to [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) with a Matrix client (via matrix.org's IRC bridge) -* use freenode's [*webchat*](http://webchat.freenode.net/?channels=bizhawk), an IRC client in a webpage +* use freenode's [web-based IRC client](http://webchat.freenode.net/?channels=bizhawk) If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From 462a0c59897dedada120789c27d305be9408bcb1 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:50:10 +1000 Subject: [PATCH 222/440] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 12121e3b0b..559f72e71a 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,9 @@ Amstrad CPC, Magnavox Odyssey², and Sony PSP emulation are works-in-progress an ## Support and troubleshooting -A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: +A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk wiki](http://tasvideos.org/Bizhawk.html). + +If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: * with an IRC client, join channel `#bizhawk` on `chat.freenode.net:6697` * connect to [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) with a Matrix client (via matrix.org's IRC bridge) * use freenode's [web-based IRC client](http://webchat.freenode.net/?channels=bizhawk) From 9791df8801ca642e8807a355a0f9f6b82c6b9143 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:51:32 +1000 Subject: [PATCH 223/440] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 559f72e71a..8f6bfa0786 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A multi-system emulator written in C#. As well as quality-of-life features for c [![GitHub latest release](https://img.shields.io/github/release/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/releases/latest) [![dev builds | AppVeyor](https://img.shields.io/badge/dev_builds-AppVeyor-orange.svg?logo=appveyor&logoColor=333333&style=popout)](https://ci.appveyor.com/project/zeromus/bizhawk-udexo/history) [![Windows prereqs | GitHub](https://img.shields.io/badge/Windows_prereqs-GitHub-darkred.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk-Prereqs/releases/latest) +[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) *** @@ -285,9 +286,7 @@ BizHawk is Open Source Software, so you're free to modify it however you please, Not a programmer? Something as simple as reproducing bugs with different software versions is still very helpful! See [*Testing*](#testing) above to learn about dev builds if you'd rather help us get the next release out. -If you'd like to fix bugs, check the issue tracker here on GitHub: - -[![GitHub open issues counter](https://img.shields.io/github/issues-raw/TASVideos/BizHawk.svg?logo=github&logoColor=333333&style=popout)](https://github.com/TASVideos/BizHawk/issues) +If you'd like to fix bugs, check the [issue tracker](https://github.com/TASVideos/BizHawk/issues) here on GitHub. It's a good idea to check if anyone is already working on an issue by asking on IRC (see [*Support*](#support-and-troubleshooting) above). From 777d4c6a81eb00d1069108daab3f04552a4dc7b7 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 25 Jan 2019 22:53:45 +1000 Subject: [PATCH 224/440] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f6bfa0786..cf537dcd71 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ A short [FAQ](http://tasvideos.org/Bizhawk/FAQ.html) is provided on the [BizHawk If your problem is one of the many not answered there, and you can't find it in the [issue tracker search](https://github.com/TASVideos/BizHawk/issues?q=is%3Aissue+ISSUE_KEYWORDS), check the [BizHawk forum](http://tasvideos.org/forum/viewforum.php?f=64) at TASVideos, or ask on IRC: * with an IRC client, join channel `#bizhawk` on `chat.freenode.net:6697` -* connect to [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) with a Matrix client (via matrix.org's IRC bridge) +* with a Matrix client, connect to [#freenode_#bizhawk:matrix.org](https://matrix.to/#/#freenode_#bizhawk:matrix.org) (via matrix.org's IRC bridge) * use freenode's [web-based IRC client](http://webchat.freenode.net/?channels=bizhawk) If there's no easy solution, what you've got is a bug. Or maybe a feature request. Either way, [open a new issue](https://github.com/TASVideos/BizHawk/issues/new) (you'll need a GitHub account, signup is very fast). From 76070cd89dce2e88ebf9afc28db3239adbeae1e5 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 25 Jan 2019 15:45:15 +0000 Subject: [PATCH 225/440] OCD: Fix non-critial compiler warnings in my code --- .../config/AmstradCPC/AmstradCPCPokeMemory.cs | 2 -- .../config/ZXSpectrum/ZXSpectrumPokeMemory.cs | 2 -- .../AmstradCPC/AmstradCPC.ISettable.cs | 1 - .../AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs | 22 +++++++++---------- .../Hardware/Display/AmstradGateArray.cs | 19 ++++++++-------- .../Hardware/SoundOutput/AY38912.cs | 4 ++-- .../AmstradCPC/Machine/GateArrayBase.cs | 10 ++++----- .../AmstradCPC/Media/Tape/CDT/CdtConverter.cs | 5 +++-- .../AmstradCPC/Media/Tape/TapeDataBlock.cs | 2 ++ .../Hardware/Disk/NECUPD765.FDC.cs | 17 +++++++++----- .../Hardware/Input/CursorJoystick.cs | 4 ++-- .../Hardware/Input/SinclairJoystick1.cs | 4 ++-- .../Hardware/Input/SinclairJoystick2.cs | 4 ++-- .../Media/Disk/IPFFormat/IPFFloppyDisk.cs | 2 +- .../Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs | 4 ++-- .../Media/Tape/TAP/TapConverter.cs | 2 +- .../Media/Tape/TZX/TzxConverter.cs | 5 +++-- .../Media/Tape/TapeDataBlock.cs | 3 +++ .../Media/Tape/WAV/WavConverter.cs | 4 ++-- .../SinclairSpectrum/ZXSpectrum.ISettable.cs | 2 +- .../DiscFormats/MDS_Format.cs | 6 ++--- 21 files changed, 65 insertions(+), 59 deletions(-) diff --git a/BizHawk.Client.EmuHawk/config/AmstradCPC/AmstradCPCPokeMemory.cs b/BizHawk.Client.EmuHawk/config/AmstradCPC/AmstradCPCPokeMemory.cs index ba99cd60c5..8175e472ad 100644 --- a/BizHawk.Client.EmuHawk/config/AmstradCPC/AmstradCPCPokeMemory.cs +++ b/BizHawk.Client.EmuHawk/config/AmstradCPC/AmstradCPCPokeMemory.cs @@ -10,8 +10,6 @@ namespace BizHawk.Client.EmuHawk { public partial class AmstradCPCPokeMemory : Form { - private AmstradCPC.AmstradCPCSettings _settings; - public AmstradCPCPokeMemory() { InitializeComponent(); diff --git a/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs index de0c799f24..9c3ec12f96 100644 --- a/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs +++ b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs @@ -10,8 +10,6 @@ namespace BizHawk.Client.EmuHawk { public partial class ZXSpectrumPokeMemory : Form { - private ZXSpectrum.ZXSpectrumSettings _settings; - public ZXSpectrumPokeMemory() { InitializeComponent(); diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.ISettable.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.ISettable.cs index bea48eedea..d6960d93e0 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.ISettable.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/AmstradCPC.ISettable.cs @@ -238,7 +238,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC // output the data splitting and tabbing as neccessary var arr = d.Value.Split(' '); - int cnt = 0; List builder = new List(); string working = ""; diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs index 54510a10fe..96815e78f3 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Disk/NECUPD765.FDC.cs @@ -394,6 +394,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC sectorSize = 0x80 << ActiveCommandParams.SectorSize; } + var mtc = maxTransferCap; + // get the current track var track = ActiveDrive.Disk.DiskTracks.Where(a => a.TrackNumber == ActiveDrive.CurrentTrackID).FirstOrDefault(); @@ -655,6 +657,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC int buffPos = 0; int sectorSize = 0; int maxTransferCap = 0; + if (maxTransferCap > 0) { } // calculate requested size of data required if (ActiveCommandParams.SectorSize == 0) @@ -967,6 +970,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC int buffPos = 0; int sectorSize = 0; int maxTransferCap = 0; + if (maxTransferCap > 0) { } // calculate requested size of data required if (ActiveCommandParams.SectorSize == 0) @@ -1031,7 +1035,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC break; } - FloppyDisk.Sector sector = null; + //FloppyDisk.Sector sector = null; ActiveDrive.SectorIndex = 0; int secCount = 0; @@ -1371,7 +1375,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC // get the first sector var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { if (track.Sectors[s].SectorID == endSecID) @@ -1422,7 +1426,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC byte endSecID = ActiveCommandParams.EOT; bool lastSec = false; var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { @@ -1664,7 +1668,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC // get the first sector var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { if (track.Sectors[s].SectorID == endSecID) @@ -1715,7 +1719,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC byte endSecID = ActiveCommandParams.EOT; bool lastSec = false; var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { @@ -2397,18 +2401,12 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC break; } - //if (!CheckTiming()) - //{ - // UnSetBit(MSR_EXM, ref StatusMain); - //} - return StatusMain; } - private int testCount = 0; + /// /// Handles CPU reading from the data register /// - /// private byte ReadDataRegister() { // default return value diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs index 659ca850c5..866fd627ca 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/Display/AmstradGateArray.cs @@ -1103,7 +1103,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC ScreenLines.Clear(); return ScreenBuffer; - + /* switch (borderType) { // crop to 768x272 (544) @@ -1139,18 +1139,19 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC } return croppedBuffer; */ + /* + var slWidth = BufferWidth; + return ScreenBuffer; - var slWidth = BufferWidth; - return ScreenBuffer; + break; - break; - - } - return ScreenBuffer; - } + } + */ + //return ScreenBuffer; + } - public void SetupScreenSize() + public void SetupScreenSize() { SysBufferWidth = 800; SysBufferHeight = 600; diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/AY38912.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/AY38912.cs index 240acb9a2c..2e2b2f0bc0 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/AY38912.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Hardware/SoundOutput/AY38912.cs @@ -28,8 +28,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC private short[] _audioBuffer; private int _audioBufferIndex; private int _lastStateRendered; - private int _clockCyclesPerFrame; - private int _cyclesPerSample; + //private int _clockCyclesPerFrame; + //private int _cyclesPerSample; #endregion diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/GateArrayBase.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/GateArrayBase.cs index 768a377b67..cfe9fedf05 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/GateArrayBase.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Machine/GateArrayBase.cs @@ -216,14 +216,14 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC private int CurrentPen; private int ScreenMode; private int INTScanlineCnt; - private int VSYNCDelyCnt; + //private int VSYNCDelyCnt; private int[][] Lookup = new int[4][]; - private bool DoModeUpdate; + //private bool DoModeUpdate; - private int LatchedMode; - private int buffPos; + //private int LatchedMode; + //private int buffPos; public bool FrameEnd; @@ -387,7 +387,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC for (int i = 0; i < 17; i++) PenColours[i] = 0; INTScanlineCnt = 0; - VSYNCDelyCnt = 0; + //VSYNCDelyCnt = 0; } #endregion diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs index 304d53d0ab..3361d96126 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/CDT/CdtConverter.cs @@ -77,7 +77,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC tb.PauseInMS = db.PauseInMS; double multiplier = (double)4 / (double)3.5; - double cycleScale = ((40 << 16) / 35); + //double cycleScale = ((40 << 16) / 35); double origPeriods = db.DataPeriods.Count(); for (int i = 0; i < origPeriods; i++) @@ -1372,7 +1372,8 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC // get text length int strLen = data[_position++]; - string title = "Info: "; + string title = string.Empty; + title = "Info: "; switch (type) { diff --git a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs index 40efa71d1e..69086fc02d 100644 --- a/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs +++ b/BizHawk.Emulation.Cores/Computers/AmstradCPC/Media/Tape/TapeDataBlock.cs @@ -51,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC set { _blockData = value; } } + /* /// /// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization) /// Its basically tape information @@ -74,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC return data; } } + */ #region Block Meta Data diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs index 62b42c7c09..b06daddf3c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Disk/NECUPD765.FDC.cs @@ -362,6 +362,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // calculate maximum transfer capacity if (!CMD_FLAG_MF) maxTransferCap = 3328; + + if (maxTransferCap == 0) { } } else { @@ -655,6 +657,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum int buffPos = 0; int sectorSize = 0; int maxTransferCap = 0; + if (maxTransferCap > 0) { } // calculate requested size of data required if (ActiveCommandParams.SectorSize == 0) @@ -967,6 +970,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum int buffPos = 0; int sectorSize = 0; int maxTransferCap = 0; + if (maxTransferCap > 0) { } // calculate requested size of data required if (ActiveCommandParams.SectorSize == 0) @@ -1031,7 +1035,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; } - FloppyDisk.Sector sector = null; + //FloppyDisk.Sector sector = null; ActiveDrive.SectorIndex = 0; int secCount = 0; @@ -1371,7 +1375,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // get the first sector var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { if (track.Sectors[s].SectorID == endSecID) @@ -1422,7 +1426,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum byte endSecID = ActiveCommandParams.EOT; bool lastSec = false; var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { @@ -1664,7 +1668,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // get the first sector var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { if (track.Sectors[s].SectorID == endSecID) @@ -1715,7 +1719,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum byte endSecID = ActiveCommandParams.EOT; bool lastSec = false; var track = ActiveDrive.Disk.DiskTracks[ActiveCommandParams.Cylinder]; - int secIndex = 0; + //int secIndex = 0; for (int s = 0; s < track.Sectors.Length; s++) { @@ -2404,7 +2408,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return StatusMain; } - private int testCount = 0; + + //private int testCount = 0; /// /// Handles CPU reading from the data register /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs index e0828551f2..68606406ad 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/CursorJoystick.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public class CursorJoystick : IJoystick { - private int _joyLine; + //private int _joyLine; private SpectrumBase _machine; #region Construction @@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public CursorJoystick(SpectrumBase machine, int playerNumber) { _machine = machine; - _joyLine = 0; + //_joyLine = 0; _playerNumber = playerNumber; ButtonCollection = new List diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs index e224646913..1b5cc0b779 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick1.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public class SinclairJoystick1 : IJoystick { - private int _joyLine; + //private int _joyLine; private SpectrumBase _machine; #region Construction @@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public SinclairJoystick1(SpectrumBase machine, int playerNumber) { _machine = machine; - _joyLine = 0; + //_joyLine = 0; _playerNumber = playerNumber; ButtonCollection = new List diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs index 6533e76f23..4c391b41a8 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/SinclairJoystick2.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public class SinclairJoystick2 : IJoystick { - private int _joyLine; + //private int _joyLine; private SpectrumBase _machine; #region Construction @@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public SinclairJoystick2(SpectrumBase machine, int playerNumber) { _machine = machine; - _joyLine = 0; + //_joyLine = 0; _playerNumber = playerNumber; ButtonCollection = new List diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs index f99c0ae179..cebfd3ec04 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs @@ -59,7 +59,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } catch (Exception ex) { - + var e = ex.ToString(); } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs index d46908a73d..953ec8d4b1 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/UDIFormat/UDI1_0FloppyDisk.cs @@ -141,9 +141,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum s1Pos += blockSize; } } - catch (Exception ex) + catch (Exception) { - + } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs index 97e1b448cf..a9ab6a895a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TAP/TapConverter.cs @@ -335,7 +335,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } // add block pause - int actualPause = PAUSE_MS * 1000; + //int actualPause = PAUSE_MS * 1000; //dataPeriods.Add(actualPause); // default pause for tap files diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs index 052be1824f..1eca78ec5a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TZX/TzxConverter.cs @@ -1312,9 +1312,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // get text length int strLen = data[_position++]; - string title = "Info: "; + string title = String.Empty; + title = "Info: "; - switch (type) + switch (type) { case 0x00: title = "Full Title: "; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs index adcc0eee97..82019ccf88 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs @@ -51,6 +51,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum set { _blockData = value; } } + /* + /// /// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization) /// Its basically tape information @@ -74,6 +76,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return data; } } + */ #region Block Meta Data diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs index 07c8d3e300..030900e3c1 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/WAV/WavConverter.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// Position counter /// - private int _position = 0; + //private int _position = 0; #region Construction @@ -91,7 +91,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum "This is not a valid WAV format file"); } - _position = 0; + //_position = 0; MemoryStream stream = new MemoryStream(); stream.Write(data, 0, data.Length); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs index 1e8e491ca6..096938717d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs @@ -390,7 +390,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // output the data splitting and tabbing as neccessary var arr = d.Value.Split(' '); - int cnt = 0; + //int cnt = 0; List builder = new List(); string working = ""; diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs index 27699da2d1..7794530401 100644 --- a/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs +++ b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs @@ -840,7 +840,7 @@ namespace BizHawk.Emulation.DiscSystem currBlobIndex++; mdfBlob = disc.DisposableResources[currBlobIndex] as Disc.Blob_RawFile; - int userSector = 2048; + //int userSector = 2048; switch (track.SectorSize) { case 2448: @@ -848,7 +848,7 @@ namespace BizHawk.Emulation.DiscSystem { Policy = IN_DiscMountPolicy }; - userSector = 2352; + //userSector = 2352; break; case 2048: default: @@ -856,7 +856,7 @@ namespace BizHawk.Emulation.DiscSystem { Policy = IN_DiscMountPolicy }; - userSector = 2048; + //userSector = 2048; break; //throw new Exception("Not supported: Sector Size " + track.SectorSize); From 198187748729536df5486dc62db434f8b84e2d12 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 27 Jan 2019 17:18:16 -0600 Subject: [PATCH 226/440] NESHawk: Remove GOTOs --- .../Consoles/Nintendo/NES/Boards/ExROM.cs | 6 ++- .../Consoles/Nintendo/NES/PPU.cs | 39 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs index ce0e72510f..b1a561e271 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/ExROM.cs @@ -255,7 +255,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // top 2 bits of address come from chr_reg_high bank_1k += chr_reg_high << 8; ofs = addr & (4 * 1024 - 1); - goto MAPPED; + + bank_1k &= chr_bank_mask_1k; + addr = (bank_1k << 10) | ofs; + return addr; } if (NES.ppu.reg_2000.obj_size_16) @@ -278,7 +281,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES bank_1k = a_banks_1k[bank_1k]; } - MAPPED: bank_1k &= chr_bank_mask_1k; addr = (bank_1k<<10)|ofs; return addr; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index b04744f5f8..c3341b15ab 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -105,6 +105,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int sum = 0; int ymin = Math.Max(Math.Max(y - radius, ppur.status.sl - 20), 0); + if (ymin > 239) { ymin = 239; } int ymax = Math.Min(y + radius, 239); int xmin = Math.Max(x - radius, 0); int xmax = Math.Min(x + radius, 255); @@ -112,21 +113,39 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int ystop = ppur.status.sl - 2; int xstop = ppur.status.cycle - 20; - for (int j = ymin; j <= ymax; j++) + bool all_stop = false; + + int j = ymin; + int i = xmin; + short s = 0; + short palcolor = 0; + short intensity = 0; + + if (j >= ystop && i >= xstop || j > ystop) { all_stop = true; } + + while (!all_stop) { - for (int i = xmin; i <= xmax; i++) + s = xbuf[j * 256 + i]; + palcolor = (short)(s & 0x3F); + intensity = (short)((s >> 6) & 0x7); + + sum += _currentLuma[palcolor]; + + i++; + if (i > xmax) { - if (j >= ystop && i >= xstop || j > ystop) - goto loopout; + i = xmin; + j++; - short s = xbuf[j * 256 + i]; - - short palcolor = (short)(s & 0x3F); - short intensity = (short)((s >> 6) & 0x7); - sum += _currentLuma[palcolor]; + if (j > ymax) + { + all_stop = true; + } } + + if (j >= ystop && i >= xstop || j > ystop) { all_stop = true; } } - loopout: + return sum >= 2000; } From 104e40d8b56a23a747e752fda4306a034cc8a3b3 Mon Sep 17 00:00:00 2001 From: feos Date: Tue, 29 Jan 2019 13:47:01 +0300 Subject: [PATCH 227/440] update gliden64 --- libmupen64plus/GLideN64 | 2 +- output/dll/mupen64plus-video-GLideN64.dll | Bin 2106880 -> 2124800 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libmupen64plus/GLideN64 b/libmupen64plus/GLideN64 index 57ba873c5e..ee91d9bf82 160000 --- a/libmupen64plus/GLideN64 +++ b/libmupen64plus/GLideN64 @@ -1 +1 @@ -Subproject commit 57ba873c5e117a42f94299cb7ddaa1066249b416 +Subproject commit ee91d9bf823457e9dcb1fe8f1213bbcf5a6f675b diff --git a/output/dll/mupen64plus-video-GLideN64.dll b/output/dll/mupen64plus-video-GLideN64.dll index c8eb531227c68a9da295708ffd0382d69d6f56c3..73298dca9a74bb601874e00340698c2a6524fb60 100644 GIT binary patch literal 2124800 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%0D%yLbgY3~QLAw_{H;_DuVOl`eVT^f#V-fe_j6 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 z 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