using System; using System.Collections.Generic; using System.Linq; using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.PCEngine { public enum PceControllerType { Unplugged, GamePad } public class PceControllerDeck { private static readonly Type[] Implementors = { typeof(UnpluggedController), // Order must match PceControllerType enum values typeof(StandardController) }; public PceControllerDeck( PceControllerType controller1, PceControllerType controller2, PceControllerType controller3, PceControllerType controller4, PceControllerType controller5) { _port1 = (IPort)Activator.CreateInstance(Implementors[(int)controller1], 1); _port2 = (IPort)Activator.CreateInstance(Implementors[(int)controller2], 2); _port3 = (IPort)Activator.CreateInstance(Implementors[(int)controller3], 3); _port4 = (IPort)Activator.CreateInstance(Implementors[(int)controller4], 4); _port5 = (IPort)Activator.CreateInstance(Implementors[(int)controller5], 5); Definition = new ControllerDefinition { Name = "PC Engine Controller", BoolButtons = _port1.Definition.BoolButtons .Concat(_port2.Definition.BoolButtons) .Concat(_port3.Definition.BoolButtons) .Concat(_port4.Definition.BoolButtons) .Concat(_port5.Definition.BoolButtons) .ToList() }; Definition.FloatControls.AddRange(_port1.Definition.FloatControls); Definition.FloatControls.AddRange(_port2.Definition.FloatControls); Definition.FloatControls.AddRange(_port3.Definition.FloatControls); Definition.FloatControls.AddRange(_port4.Definition.FloatControls); Definition.FloatControls.AddRange(_port5.Definition.FloatControls); Definition.FloatRanges.AddRange(_port1.Definition.FloatRanges); Definition.FloatRanges.AddRange(_port2.Definition.FloatRanges); Definition.FloatRanges.AddRange(_port3.Definition.FloatRanges); Definition.FloatRanges.AddRange(_port4.Definition.FloatRanges); Definition.FloatRanges.AddRange(_port5.Definition.FloatRanges); } private readonly IPort _port1; private readonly IPort _port2; private readonly IPort _port3; private readonly IPort _port4; private readonly IPort _port5; public byte Read(int portNum, IController c, bool sel) { switch (portNum) { default: throw new ArgumentException($"Invalid {nameof(portNum)}: {portNum}"); case 1: return _port1.Read(c, sel); case 2: return _port2.Read(c, sel); case 3: return _port3.Read(c, sel); case 4: return _port4.Read(c, sel); case 5: return _port5.Read(c, sel); } } public ControllerDefinition Definition { get; } } public interface IPort { byte Read(IController c, bool sel); ControllerDefinition Definition { get; } int PortNum { get; } } public class UnpluggedController : IPort { public UnpluggedController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = new List() }; } public byte Read(IController c, bool sel) { return 0x3F; } public ControllerDefinition Definition { get; } public int PortNum { get; } } public class StandardController : IPort { public StandardController(int portNum) { PortNum = portNum; Definition = new ControllerDefinition { BoolButtons = BaseDefinition .Select(b => $"P{PortNum} " + b) .ToList() }; } public ControllerDefinition Definition { get; } public int PortNum { get; } public byte Read(IController c, bool sel) { byte result = 0x3F; if (sel == false) { if (c.IsPressed($"P{PortNum} B1")) result &= 0xFE; if (c.IsPressed($"P{PortNum} B2")) result &= 0xFD; if (c.IsPressed($"P{PortNum} Select")) result &= 0xFB; if (c.IsPressed($"P{PortNum} Run")) result &= 0xF7; } else { if (c.IsPressed($"P{PortNum} Up")) { result &= 0xFE; } if (c.IsPressed($"P{PortNum} Right")) { result &= 0xFD; } if (c.IsPressed($"P{PortNum} Down")) { result &= 0xFB; } if (c.IsPressed($"P{PortNum} Left")) { result &= 0xF7; } } return result; } private static readonly string[] BaseDefinition = { "Up", "Down", "Left", "Right", "Select", "Run", "B2", "B1" }; } }