using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using BizHawk.Common; using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.ColecoVision { /// /// Represents a controller plugged into a controller port on the Colecovision /// public interface IPort { byte Read(IController c, bool leftMode, bool updateWheel, float wheelAngle); float UpdateWheel(IController c); ControllerDefinition Definition { get; } void SyncState(Serializer ser); int PortNum { get; } } [DisplayName("Unplugged Controller")] public class UnpluggedController : IPort { public UnpluggedController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = new List() }; } public byte Read(IController c, bool left_mode, bool updateWheel, float wheelAngle) { return 0x7F; // needs checking } public ControllerDefinition Definition { get; } public void SyncState(Serializer ser) { // Do nothing } public int PortNum { get; } public float UpdateWheel(IController c) { return 0; } } [DisplayName("ColecoVision Basic Controller")] public class StandardController : IPort { public StandardController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = BaseDefinition .Select(b => "P" + PortNum + " " + b) .ToList() }; } public int PortNum { get; } public byte Read(IController c, bool leftMode, bool updateWheel, float wheelAngle) { if (leftMode) { byte retval = 0x7F; if (c.IsPressed(Definition.BoolButtons[0])) retval &= 0xFE; if (c.IsPressed(Definition.BoolButtons[1])) retval &= 0xFD; if (c.IsPressed(Definition.BoolButtons[2])) retval &= 0xFB; if (c.IsPressed(Definition.BoolButtons[3])) retval &= 0xF7; if (c.IsPressed(Definition.BoolButtons[4])) retval &= 0x3F; return retval; } else { byte retval = 0xF; // 0x00; if (c.IsPressed(Definition.BoolButtons[14])) retval = 0x01; if (c.IsPressed(Definition.BoolButtons[10])) retval = 0x02; if (c.IsPressed(Definition.BoolButtons[11])) retval = 0x03; // 0x04; if (c.IsPressed(Definition.BoolButtons[13])) retval = 0x05; if (c.IsPressed(Definition.BoolButtons[16])) retval = 0x06; if (c.IsPressed(Definition.BoolButtons[8])) retval = 0x07; // 0x08; if (c.IsPressed(Definition.BoolButtons[17])) retval = 0x09; if (c.IsPressed(Definition.BoolButtons[6])) retval = 0x0A; if (c.IsPressed(Definition.BoolButtons[15])) retval = 0x0B; if (c.IsPressed(Definition.BoolButtons[9])) retval = 0x0C; if (c.IsPressed(Definition.BoolButtons[7])) retval = 0x0D; if (c.IsPressed(Definition.BoolButtons[12])) retval = 0x0E; if (c.IsPressed(Definition.BoolButtons[5]) == false) retval |= 0x40; retval |= 0x30; // always set these bits return retval; } } public ControllerDefinition Definition { get; } public void SyncState(Serializer ser) { // Nothing todo, I think } private static readonly string[] BaseDefinition = { "Up", "Right", "Down", "Left", "L", "R", "Key 0", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Pound", "Star" }; public float UpdateWheel(IController c) { return 0; } } [DisplayName("Turbo Controller")] public class ColecoTurboController : IPort { public ColecoTurboController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = BaseBoolDefinition .Select(b => "P" + PortNum + " " + b) .ToList(), FloatControls = { "P" + PortNum + " Disc X", "P" + PortNum + " Disc Y" }, FloatRanges = { new[] { -127.0f, 0, 127.0f }, new[] { -127.0f, 0, 127.0f } } }; } public int PortNum { get; } public ControllerDefinition Definition { get; } public byte Read(IController c, bool leftMode, bool updateWheel, float wheelAngle) { if (leftMode) { byte retval = 0x4F; if (c.IsPressed(Definition.BoolButtons[0])) retval &= 0x3F; float x = c.GetFloat(Definition.FloatControls[0]); float y = c.GetFloat(Definition.FloatControls[1]); float angle; if (updateWheel) { angle = wheelAngle; } else { angle = CalcDirection(x, y); } byte temp2 = 0; int temp1 = (int)Math.Floor(angle / 1.25); temp1 = temp1 % 4; if (temp1 == 0) { temp2 = 0x10; } if (temp1 == 1) { temp2 = 0x30; } if (temp1 == 2) { temp2 = 0x20; } if (temp1 == 3) { temp2 = 0x00; } retval |= temp2; return retval; } else { byte retval = 0x7F; return retval; } } public void SyncState(Serializer ser) { // Nothing todo, I think } private static readonly string[] BaseBoolDefinition = { "Pedal" }; // x and y are both assumed to be in [-127, 127] // x increases from left to right // y increases from top to bottom private static float CalcDirection(float x, float y) { y = -y; // vflip to match the arrangement of FloatControllerButtons // the wheel is arranged in a grey coded configuration of sensitivity ~2.5 degrees // for each signal // so overall the value returned changes every 1.25 degrees float angle = (float)(Math.Atan2(y, x) * 180.0/Math.PI); if (angle < 0) { angle = 360 + angle; } return angle; } public float UpdateWheel(IController c) { float x = c.GetFloat(Definition.FloatControls[0]); float y = c.GetFloat(Definition.FloatControls[1]); return CalcDirection(x, y); } } [DisplayName("Super Action Controller")] public class ColecoSuperActionController : IPort { public ColecoSuperActionController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = BaseBoolDefinition .Select(b => "P" + PortNum + " " + b) .ToList(), FloatControls = { "P" + PortNum + " Disc X"}, FloatRanges = { new[] { -360.0f, 0, 360.0f }} }; } public int PortNum { get; private set; } public ControllerDefinition Definition { get; private set; } public byte Read(IController c, bool left_mode, bool updateWheel, float wheelAngle) { if (left_mode) { byte retval = 0x4F; if (c.IsPressed(Definition.BoolButtons[0])) retval &= 0xFE; if (c.IsPressed(Definition.BoolButtons[1])) retval &= 0xFD; if (c.IsPressed(Definition.BoolButtons[2])) retval &= 0xFB; if (c.IsPressed(Definition.BoolButtons[3])) retval &= 0xF7; if (c.IsPressed(Definition.BoolButtons[4])) retval &= 0x3F; float x = c.GetFloat(Definition.FloatControls[0]); float y = c.GetFloat(Definition.FloatControls[1]); float angle; if (updateWheel) { angle = wheelAngle; } else { angle = CalcDirection(x, y); } byte temp2 = 0; int temp1 = (int)Math.Floor(angle / 1.25); temp1 = temp1 % 4; if (temp1 == 0) { temp2 = 0x10; } if (temp1 == 1) { temp2 = 0x30; } if (temp1 == 2) { temp2 = 0x20; } if (temp1 == 3) { temp2 = 0x00; } retval |= temp2; return retval; } else { byte retval = 0xF; // 0x00; if (c.IsPressed(Definition.BoolButtons[14])) retval = 0x01; if (c.IsPressed(Definition.BoolButtons[10])) retval = 0x02; if (c.IsPressed(Definition.BoolButtons[11])) retval = 0x03; // 0x04; if (c.IsPressed(Definition.BoolButtons[13])) retval = 0x05; if (c.IsPressed(Definition.BoolButtons[16])) retval = 0x06; if (c.IsPressed(Definition.BoolButtons[8])) retval = 0x07; // 0x08; if (c.IsPressed(Definition.BoolButtons[17])) retval = 0x09; if (c.IsPressed(Definition.BoolButtons[6])) retval = 0x0A; if (c.IsPressed(Definition.BoolButtons[15])) retval = 0x0B; if (c.IsPressed(Definition.BoolButtons[9])) retval = 0x0C; if (c.IsPressed(Definition.BoolButtons[7])) retval = 0x0D; if (c.IsPressed(Definition.BoolButtons[12])) retval = 0x0E; // extra buttons for SAC if (c.IsPressed(Definition.BoolButtons[18])) retval = 0x04; if (c.IsPressed(Definition.BoolButtons[19])) retval = 0x08; if (c.IsPressed(Definition.BoolButtons[5]) == false) retval |= 0x40; retval |= 0x30; // always set these bits return retval; } } public void SyncState(Serializer ser) { // nothing to do } private static readonly string[] BaseBoolDefinition = { "Up", "Right", "Down", "Left", "Yellow", "Red", "Key 0", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Pound", "Star", "Purple", "Blue" }; // x and y are both assumed to be in [-127, 127] // x increases from left to right // y increases from top to bottom private static float CalcDirection(float x, float y) { y = -y; // vflip to match the arrangement of FloatControllerButtons // the wheel is arranged in a grey coded configuration of sensitivity ~2.5 degrees // for each signal // so overall the value returned changes every 1.25 degrees float angle = (float)(Math.Atan2(y, x) * 180.0 / Math.PI); if (angle < 0) { angle = 360 + angle; } return angle; } public float UpdateWheel(IController c) { float x = c.GetFloat(Definition.FloatControls[0]); float y = c.GetFloat(Definition.FloatControls[1]); return CalcDirection(x, y); } } }