From c863d57113101e3817cc18b96b04a9735b527606 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 28 Apr 2014 00:39:40 +0000 Subject: [PATCH] Better color coding of input display, auto-holds show red, previous frame shows orange, restore ability to show immediate input, also fix but in autofire-autohold --- BizHawk.Client.Common/ControllerBinding.cs | 13 ++ BizHawk.Client.Common/movie/InputAdapters.cs | 125 +++++++++++++--- .../DisplayManager/OSDManager.cs | 136 ++++++++++++++---- BizHawk.Client.EmuHawk/MainForm.cs | 5 + 4 files changed, 228 insertions(+), 51 deletions(-) diff --git a/BizHawk.Client.Common/ControllerBinding.cs b/BizHawk.Client.Common/ControllerBinding.cs index da454f1cce..8502075240 100644 --- a/BizHawk.Client.Common/ControllerBinding.cs +++ b/BizHawk.Client.Common/ControllerBinding.cs @@ -37,6 +37,19 @@ namespace BizHawk.Client.Common return _buttons[button]; } + public bool AnyPressed + { + get + { + if (_buttons.Any(x => x.Value)) + { + return true; + } + + return _floatButtons.Any(x => x.Value != 0); + } + } + public float GetFloat(string name) { return _floatButtons[name]; } // Looks for bindings which are activated by the supplied physical button. diff --git a/BizHawk.Client.Common/movie/InputAdapters.cs b/BizHawk.Client.Common/movie/InputAdapters.cs index 103a5ac5b5..77d474ffab 100644 --- a/BizHawk.Client.Common/movie/InputAdapters.cs +++ b/BizHawk.Client.Common/movie/InputAdapters.cs @@ -202,7 +202,72 @@ namespace BizHawk.Client.Common } - public class StickyXorAdapter : IController + public class AndAdapter : IController + { + public bool IsPressed(string button) + { + return this[button]; + } + + // pass floats solely from the original source + // this works in the code because SourceOr is the autofire controller + public float GetFloat(string name) { return Source.GetFloat(name); } + + public IController Source { get; set; } + public IController SourceAnd { get; set; } + public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } } + + public bool this[string button] + { + get + { + return Source[button] & SourceAnd[button]; + } + + set + { + throw new InvalidOperationException(); + } + } + } + + // Used by input display, to determine if either autofire or regular stickies are "in effect" because we color this scenario differently + public class StickyOrAdapter : IController + { + public bool IsPressed(string button) + { + return this[button]; + } + + // pass floats solely from the original source + // this works in the code because SourceOr is the autofire controller + public float GetFloat(string name) { return 0.0F; } // Floats don't make sense in sticky land + + public ISticky Source { get; set; } + public ISticky SourceStickyOr { get; set; } + public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } } + + public bool this[string button] + { + get + { + return Source.StickyIsInEffect(button) || + SourceStickyOr.StickyIsInEffect(button); + } + + set + { + throw new InvalidOperationException(); + } + } + } + + public interface ISticky : IController + { + bool StickyIsInEffect(string button); + } + + public class StickyXorAdapter : IController, ISticky { protected HashSet stickySet = new HashSet(); @@ -216,7 +281,10 @@ namespace BizHawk.Client.Common public bool Locked { get; set; } // Pretty much a hack, - public bool IsPressed(string button) { return this[button]; } + public bool IsPressed(string button) + { + return this[button]; + } // if SetFloat() is called (typically virtual pads), then that float will entirely override the Source input // otherwise, the source is passed thru. @@ -259,6 +327,20 @@ namespace BizHawk.Client.Common } } + /// + /// Determines if a sticky is current mashing the button itself, + /// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false + /// + public bool StickyIsInEffect(string button) + { + if (IsSticky(button)) + { + return !Source.IsPressed(button); + } + + return false; + } + public void SetSticky(string button, bool isSticky) { if (isSticky) @@ -314,7 +396,7 @@ namespace BizHawk.Client.Common private List _justPressed = new List(); } - public class AutoFireStickyXorAdapter : IController + public class AutoFireStickyXorAdapter : IController, ISticky { public int On { get; set; } public int Off { get; set; } @@ -340,22 +422,7 @@ namespace BizHawk.Client.Common public bool IsPressed(string button) { - if (_stickySet.Contains(button)) - { - var a = (Global.Emulator.Frame - buttonStarts[button]) % (On + Off); - if (a < On) - { - return this[button]; - } - else - { - return false; - } - } - else - { - return Source[button]; - } + return this[button]; } public bool this[string button] @@ -369,14 +436,14 @@ namespace BizHawk.Client.Common var a = (Global.Emulator.Frame - buttonStarts[button]) % (On + Off); if (a < On) { - source ^= true; + return source ^= true; } else { - source ^= false; + return source ^= false; } } - + return source; } @@ -442,6 +509,20 @@ namespace BizHawk.Client.Common _justPressed = buttons; } + /// + /// Determines if a sticky is current mashing the button itself, + /// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false + /// + public bool StickyIsInEffect(string button) + { + if (Source.IsPressed(button)) + { + return false; + } + + return (IsPressed(button)); // Shortcut logic since we know the Source isn't pressed, Ispressed can only return true if the autofire sticky is in effect for this frame + } + private List _justPressed = new List(); } diff --git a/BizHawk.Client.EmuHawk/DisplayManager/OSDManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/OSDManager.cs index a519b6e44f..5b42c3e936 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/OSDManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/OSDManager.cs @@ -221,21 +221,82 @@ namespace BizHawk.Client.EmuHawk } } - - public string MakeInputDisplay() + public string InputStrMovie() { - StringBuilder sb; - if (!Global.MovieSession.Movie.IsActive || Global.MovieSession.Movie.IsFinished) - { - sb = new StringBuilder(Global.GetOutputControllersAsMnemonic()); - } - else - { - sb = new StringBuilder(Global.MovieSession.Movie.GetInput(Global.Emulator.Frame - 1)); - } - + var sb = new StringBuilder(Global.GetOutputControllersAsMnemonic()); sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); + return sb.ToString(); + } + public string InputStrImmediate() + { + var mg = new MnemonicsGenerator(); + mg.SetSource(Global.AutofireStickyXORAdapter); + + var sb = new StringBuilder(mg.GetControllersAsMnemonic()); + sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); + return sb.ToString(); + } + + public string InputPrevious() + { + var sb = new StringBuilder(Global.MovieSession.Movie.GetInput(Global.Emulator.Frame - 1)); + sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); + return sb.ToString(); + } + + public string InputStrOrAll() + { + var m = new MovieControllerAdapter { Type = Global.MovieSession.MovieControllerAdapter.Type }; + m.SetControllersAsMnemonic( + Global.MovieSession.Movie.GetInput(Global.Emulator.Frame - 1)); + + var orAdaptor = new ORAdapter() + { + Source = Global.AutofireStickyXORAdapter, + SourceOr = m + }; + + var mg = new MnemonicsGenerator(); + mg.SetSource(orAdaptor); + + var sb = new StringBuilder(mg.GetControllersAsMnemonic()); + sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); + return sb.ToString(); + } + + public string InputStrSticky() + { + var stickyOr = new StickyOrAdapter + { + Source = Global.StickyXORAdapter, + SourceStickyOr = Global.AutofireStickyXORAdapter + }; + + var mg = new MnemonicsGenerator(); + mg.SetSource(stickyOr); + var sb = new StringBuilder(mg.GetControllersAsMnemonic()); + sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); + return sb.ToString(); + } + + public string MakeIntersectImmediatePrevious() + { + var m = new MovieControllerAdapter { Type = Global.MovieSession.MovieControllerAdapter.Type }; + m.SetControllersAsMnemonic( + Global.MovieSession.Movie.GetInput(Global.Emulator.Frame - 1)); + + var andAdaptor = new AndAdapter + { + Source = Global.AutofireStickyXORAdapter, + SourceAnd = m + }; + + var mg = new MnemonicsGenerator(); + mg.SetSource(andAdaptor); + + var sb = new StringBuilder(mg.GetControllersAsMnemonic()); + sb.Replace(".", " ").Replace("|", "").Replace(" 000, 000", " "); return sb.ToString(); } @@ -245,10 +306,8 @@ namespace BizHawk.Client.EmuHawk { return "Rerecord Count: " + Global.MovieSession.Movie.Header.Rerecords; } - else - { - return string.Empty; - } + + return string.Empty; } private void DrawOsdMessage(IBlitter g, string message, Color color, float x, float y) @@ -273,22 +332,41 @@ namespace BizHawk.Client.EmuHawk if (Global.Config.DisplayInput) { - string input = MakeInputDisplay(); - Color c; - float x = GetX(g, Global.Config.DispInpx, Global.Config.DispInpanchor, input); - float y = GetY(g, Global.Config.DispInpy, Global.Config.DispInpanchor, input); - if (Global.MovieSession.Movie.IsPlaying && !Global.MovieSession.Movie.IsRecording) + if (Global.MovieSession.Movie.IsPlaying && !Global.MovieSession.Movie.IsFinished) { - c = Color.FromArgb(Global.Config.MovieInput); - } - else - { - c = Color.FromArgb(Global.Config.MessagesColor); + var input = InputStrMovie(); + var x = GetX(g, Global.Config.DispInpx, Global.Config.DispInpanchor, input); + var y = GetY(g, Global.Config.DispInpy, Global.Config.DispInpanchor, input); + Color c = Color.FromArgb(Global.Config.MovieInput); + g.DrawString(input, MessageFont, Color.Black, x + 1, y + 1); + g.DrawString(input, MessageFont, c, x, y); } - // TODO: this needs to be multi-colored and more intelligent: https://code.google.com/p/bizhawk/issues/detail?id=52 - g.DrawString(input, MessageFont, Color.Black, x + 1, y + 1); - g.DrawString(input, MessageFont, c, x, y); + else // TODO: message config -- allow setting of "previous", "mixed", and "auto" + { + var bgStr = InputStrOrAll(); + var x = GetX(g, Global.Config.DispInpx, Global.Config.DispInpanchor, bgStr); + var y = GetY(g, Global.Config.DispInpy, Global.Config.DispInpanchor, bgStr); + g.DrawString(bgStr, MessageFont, Color.Black, x + 1, y + 1); + + + + var previousStr = InputPrevious(); + var pColor = Color.Orange; + g.DrawString(previousStr, MessageFont, pColor, x, y); + + + var immediate = InputStrImmediate(); + Color immediateColor = Color.FromArgb(Global.Config.MessagesColor); + g.DrawString(immediate, MessageFont, immediateColor, x, y); + + var immediateOverlay = MakeIntersectImmediatePrevious(); + var oColor = Color.PeachPuff; + g.DrawString(immediateOverlay, MessageFont, oColor, x, y); + + var autoString = InputStrSticky(); + g.DrawString(autoString, MessageFont, Color.Pink, x, y); + } } if (Global.MovieSession.MultiTrack.IsActive) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 75a341426a..7261fdf14a 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -448,6 +448,11 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.LuaConsole.ResumeScripts(false); } + if (Global.Config.DisplayInput) // Input display wants to update even while paused + { + GlobalWin.DisplayManager.NeedsToPaint = true; + } + StepRunLoop_Core(); StepRunLoop_Throttle();