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); + } + } +}