Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify SGB related UIs and make it possible to use SGB under Gambatte link #3635

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dd14f8e
merge SGB into a mode option of Gambatte
Fortranm Jun 18, 2022
5f95a93
merge the core choices for SGB
Fortranm Jun 18, 2022
f8b294f
GBL compatibility
Fortranm Jun 19, 2022
eecee30
rename SGB mode to SGB2 for Gambatte and fix BSNES initialization
Fortranm Jun 19, 2022
dd6abbc
SGB border in GBL
Fortranm Jun 21, 2022
7dd40dd
adjust sgb core detection
Fortranm Jun 22, 2022
511f48d
reformat controller button naming
Fortranm Jun 30, 2022
2e6f59b
adjust for 2.9
Fortranm Apr 16, 2023
2e534a9
adjust for 2.9 again
Fortranm Apr 16, 2023
ff268f3
revert changes to BSNES CoreConstructor
Fortranm Jun 23, 2023
c183e6e
one Player tab per SNES controller for SGB
Fortranm Jun 23, 2023
0a3a727
idiomatic rephrase for showAnyBorder
Fortranm Jul 12, 2023
ef87a48
no dummy for CreateSGBVideoBuffer
Fortranm Jul 12, 2023
c0ff230
fix SGB conversion in LsmvImport
Fortranm Jul 13, 2023
b2a4720
add legacy BSNES option for (S)GB
Fortranm Jul 13, 2023
e8aa24a
minor cosmetic changes
Morilli May 29, 2024
3786258
Fix `.vbm` importer when Gambatte isn't the preferred GB core
YoshiRulz May 30, 2024
0f5cc8d
Fix button mapping spaghetti
YoshiRulz May 30, 2024
b910c38
Code style nitpicks
YoshiRulz May 30, 2024
864ee92
minor cleanups in Gambatte.cs
Morilli Jun 19, 2024
c68e9db
Remove special SGB handling and mark bsnes* as GB/GBC cores
Morilli Jun 19, 2024
c56f047
remove SGB from CorePickerUIData
Fortranm Jul 1, 2024
f148272
Un-revert submodule pull
YoshiRulz Jul 1, 2024
cddb113
Un-revert other submodule pulls
YoshiRulz Jul 1, 2024
02746ef
fix the crash from Toggle Link Connection
Fortranm Jul 2, 2024
06496c6
remove inaccurate description of how Auto works for console
Fortranm Jul 4, 2024
3e401db
Merge branch 'master' into SGB-link
Fortranm Jul 4, 2024
0e32693
Remove unused import
YoshiRulz Jul 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/BizHawk.Client.Common/RomLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,11 +481,6 @@ private void LoadOther(
);
return;
}

if (_config.GbAsSgb)
{
game.System = VSystemID.Raw.SGB;
}
break;
case VSystemID.Raw.PSX when ext is ".bin":
const string FILE_EXT_CUE = ".cue";
Expand Down Expand Up @@ -851,11 +846,6 @@ private void DispatchErrorMessage(Exception ex, string system, string path)
{
DoLoadErrorCallback(ex.Message, system, path, Deterministic, LoadErrorType.MissingFirmware);
}
else if (ex is CGBNotSupportedException)
{
// failed to load SGB bios or game does not support SGB mode.
DoLoadErrorCallback("Failed to load a GB rom in SGB mode. You might try disabling SGB Mode.", system);
}
else if (ex is NoAvailableCoreException)
{
// handle exceptions thrown by the new detected systems that BizHawk does not have cores for
Expand Down
6 changes: 1 addition & 5 deletions src/BizHawk.Client.Common/config/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ public class Config
public static readonly IReadOnlyList<(string[] AppliesTo, string[] CoreNames)> CorePickerUIData = new List<(string[], string[])>
{
([ VSystemID.Raw.GB, VSystemID.Raw.GBC ],
[ CoreNames.Gambatte, CoreNames.Sameboy, CoreNames.GbHawk, CoreNames.SubGbHawk ]),
[ CoreNames.Gambatte, CoreNames.Sameboy, CoreNames.GbHawk, CoreNames.SubGbHawk, CoreNames.Bsnes, CoreNames.Bsnes115, CoreNames.SubBsnes115 ]),
([ VSystemID.Raw.GBL ],
[ CoreNames.GambatteLink, CoreNames.GBHawkLink, CoreNames.GBHawkLink3x, CoreNames.GBHawkLink4x ]),
([ VSystemID.Raw.SGB ],
[ CoreNames.Gambatte, CoreNames.Bsnes115, CoreNames.SubBsnes115, CoreNames.Bsnes ]),
([ VSystemID.Raw.GEN ],
[ CoreNames.Gpgx, CoreNames.PicoDrive ]),
([ VSystemID.Raw.N64 ],
Expand Down Expand Up @@ -387,8 +385,6 @@ public void SetWindowScaleFor(string sysID, int windowScale)
public Dictionary<string, Dictionary<string, AnalogBind>> AllTrollersAnalog { get; set; } = new Dictionary<string, Dictionary<string, AnalogBind>>();
public Dictionary<string, Dictionary<string, FeedbackBind>> AllTrollersFeedbacks { get; set; } = new Dictionary<string, Dictionary<string, FeedbackBind>>();

/// <remarks>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</remarks>
public bool GbAsSgb { get; set; }
public string LibretroCore { get; set; }

public Dictionary<string, string> PreferredCores = GenDefaultCorePreferences();
Expand Down
3 changes: 1 addition & 2 deletions src/BizHawk.Client.Common/movie/import/LsmvImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ protected override void RunImport()
break;
case "sgb_ntsc":
case "sgb_pal":
platform = VSystemID.Raw.SNES;
Config.GbAsSgb = true;
platform = VSystemID.Raw.SGB;
break;
}

Expand Down
16 changes: 12 additions & 4 deletions src/BizHawk.Client.Common/movie/import/VbmImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,15 @@ recording time in Unix epoch format
Result.Movie.HeaderEntries.Add("IsCGBMode", "1");
}

var finalCoreName = Config.PreferredCores[VSystemID.Raw.GB];
if (isSGB)
{
Result.Errors.Add("SGB imports are not currently supported");
platform = VSystemID.Raw.SGB;
if (finalCoreName is not CoreNames.Gambatte)
{
Result.Warnings.Add($"{finalCoreName} doesn't support SGB; will use {CoreNames.Gambatte}");
finalCoreName = CoreNames.Gambatte;
}
}

Result.Movie.HeaderEntries[HeaderKeys.Platform] = platform;
Expand Down Expand Up @@ -276,13 +282,15 @@ A stream of 2-byte bitvectors which indicate which buttons are pressed at each p
}
else
{
Result.Movie.HeaderEntries[HeaderKeys.Core] = Config.PreferredCores[VSystemID.Raw.GB];
switch (Config.PreferredCores[VSystemID.Raw.GB])
Result.Movie.HeaderEntries[HeaderKeys.Core] = finalCoreName;
switch (finalCoreName)
{
case CoreNames.Gambatte:
Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(new Gameboy.GambatteSyncSettings
{
ConsoleMode = is_GBC ? Gameboy.GambatteSyncSettings.ConsoleModeType.GBC : Gameboy.GambatteSyncSettings.ConsoleModeType.GB,
ConsoleMode = isSGB
? Gameboy.GambatteSyncSettings.ConsoleModeType.SGB2
: is_GBC ? Gameboy.GambatteSyncSettings.ConsoleModeType.GBC : Gameboy.GambatteSyncSettings.ConsoleModeType.GB,
});
break;
case CoreNames.GbHawk:
Expand Down
8 changes: 0 additions & 8 deletions src/BizHawk.Client.EmuHawk/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,9 @@ ToolStripItem[] CreateWindowSizeFactorSubmenus()
CoresSubMenu.DropDownItems.Add(submenu);
}
CoresSubMenu.DropDownItems.Add(new ToolStripSeparator { AutoSize = true });
var GBInSGBMenuItem = new ToolStripMenuItem { Text = "GB in SGB" };
GBInSGBMenuItem.Click += (_, _) =>
{
Config.GbAsSgb ^= true;
if (Emulator.SystemId is VSystemID.Raw.GB or VSystemID.Raw.GBC or VSystemID.Raw.SGB) FlagNeedsReboot();
};
CoresSubMenu.DropDownItems.Add(GBInSGBMenuItem);
var setLibretroCoreToolStripMenuItem = new ToolStripMenuItem { Text = "Set Libretro Core..." };
setLibretroCoreToolStripMenuItem.Click += (_, _) => RunLibretroCoreChooser();
CoresSubMenu.DropDownItems.Add(setLibretroCoreToolStripMenuItem);
CoresSubMenu.DropDownOpened += (_, _) => GBInSGBMenuItem.Checked = Config.GbAsSgb;

ToolStripMenuItemEx recentCoreSettingsSubmenu = new() { Text = "Recent" };
recentCoreSettingsSubmenu.DropDownItems.AddRange(CreateCoreSettingsSubmenus().ToArray());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class BsnesCore : IEmulator, IDebuggable, IVideoProvider, ISaveRam, IStatable, IInputPollable, IRegionable, ISettable<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings>, IBSNESForGfxDebugger, IBoardInfo
{
[CoreConstructor(VSystemID.Raw.GB)]
[CoreConstructor(VSystemID.Raw.GBC)]
YoshiRulz marked this conversation as resolved.
Show resolved Hide resolved
[CoreConstructor(VSystemID.Raw.Satellaview)]
[CoreConstructor(VSystemID.Raw.SGB)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this attribute...

[CoreConstructor(VSystemID.Raw.SNES)]
public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParameters) : this(loadParameters, false) { }
public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParameters, bool subframe = false)
Expand All @@ -29,8 +30,8 @@ public BsnesCore(CoreLoadParameters<SnesSettings, SnesSyncSettings> loadParamete
this._romPath = Path.ChangeExtension(loadParameters.Roms[0].RomPath, null);
CoreComm = loadParameters.Comm;
_syncSettings = loadParameters.SyncSettings ?? new SnesSyncSettings();
SystemId = loadParameters.Game.System;
_isSGB = SystemId == VSystemID.Raw.SGB;
_isSGB = loadParameters.Game.System is VSystemID.Raw.GB or VSystemID.Raw.GBC;
SystemId = _isSGB ? VSystemID.Raw.SGB : loadParameters.Game.System;
_currentMsuTrack = new ProxiedFile();

byte[] sgbRomData = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public class SubBsnesCore : IEmulator, ICycleTiming
{
[CoreConstructor(VSystemID.Raw.GB)]
[CoreConstructor(VSystemID.Raw.GBC)]
[CoreConstructor(VSystemID.Raw.Satellaview)]
[CoreConstructor(VSystemID.Raw.SGB)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and here...

[CoreConstructor(VSystemID.Raw.SNES)]
public SubBsnesCore(CoreLoadParameters<BsnesCore.SnesSettings, BsnesCore.SnesSyncSettings> loadParameters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ public enum ConsoleModeType
Auto,
GB,
GBC,
GBA
GBA,
SGB2,
}

[DisplayName("Console Mode")]
[Description("Pick which console to run, 'Auto' chooses from ROM header; 'GB', 'GBC', and 'GBA' chooses the respective system. Does nothing in SGB mode.")]
[Description("Picks which console to emulate.")]
[DefaultValue(ConsoleModeType.Auto)]
public ConsoleModeType ConsoleMode { get; set; }

Expand Down
16 changes: 6 additions & 10 deletions src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public partial class Gameboy : IInputPollable, IRomInfo, IGameboyCommon, ICycleT

[CoreConstructor(VSystemID.Raw.GB)]
[CoreConstructor(VSystemID.Raw.GBC)]
[CoreConstructor(VSystemID.Raw.SGB)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is SGB being removed here? BSNES/BSNESv115 still have it.

Copy link
Collaborator

@Morilli Morilli Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because for core choosing, the system is only set to SGB when the core is bsnes:

static bool IsPreferredCoreSGB(Config config)
=> config.PreferredCores[VSystemID.Raw.GB] is CoreNames.Bsnes or CoreNames.Bsnes115 or CoreNames.SubBsnes115;
if (IsPreferredCoreSGB(_config))
{
game.System = VSystemID.Raw.SGB;
}

Thinking about it, that's probably logic that could get removed too...

Copy link
Member

@CasualPokePlayer CasualPokePlayer Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this exactly end up working for say, loading a GBC only ROM into BSNES. Does it proceed to fail completely due to not finding a fallback with the SGB system ID ctor, or does it end up still picking Gambatte with the GBC system ID?

Copy link
Collaborator

@Morilli Morilli Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. It does NOT work currently for that exact reason and instead runs into this code which then no longer makes sense:

DoLoadErrorCallback("Failed to load a GB rom in SGB mode. You might try disabling SGB Mode.", system);

This comment was marked as duplicate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's more to this, and there is already broken behavior currently. I'll make an issue later.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#3960
The new issue in question for reference. The way this currently is makes sense with that proposed change.
Resolving.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and here...

public Gameboy(CoreComm comm, IGameInfo game, byte[] file, GambatteSettings settings, GambatteSyncSettings syncSettings, bool deterministic)
public Gameboy(CoreComm comm, GameInfo game, byte[] file, GambatteSettings settings, GambatteSyncSettings syncSettings, bool deterministic)
{
_serviceProvider = new(this);
_serviceProvider.Register<IDisassemblable>(_disassembler);
Expand Down Expand Up @@ -58,6 +57,10 @@ public Gameboy(CoreComm comm, IGameInfo game, byte[] file, GambatteSettings sett
case GambatteSyncSettings.ConsoleModeType.GBA:
flags |= LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG;
break;
case GambatteSyncSettings.ConsoleModeType.SGB2:
flags |= LibGambatte.LoadFlags.SGB_MODE;
IsSgb = true;
break;
case GambatteSyncSettings.ConsoleModeType.Auto:
if (game.System == VSystemID.Raw.GBC)
flags |= LibGambatte.LoadFlags.CGB_MODE;
Expand All @@ -66,13 +69,6 @@ public Gameboy(CoreComm comm, IGameInfo game, byte[] file, GambatteSettings sett
throw new InvalidOperationException();
}

if (game.System == VSystemID.Raw.SGB)
{
flags &= ~(LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG);
flags |= LibGambatte.LoadFlags.SGB_MODE;
IsSgb = true;
}

IsCgb = (flags & LibGambatte.LoadFlags.CGB_MODE) == LibGambatte.LoadFlags.CGB_MODE;

bool ForceBios()
Expand Down Expand Up @@ -636,7 +632,7 @@ public IGPUMemoryAreas LockGPU()
Vram = _vram,
Oam = _oam,
Sppal = _sppal,
Bgpal = _bgpal,
Bgpal = _bgpal,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;

namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
Expand All @@ -17,16 +18,26 @@ public bool FrameAdvance(IController controller, bool render, bool rendersound =

foreach (var s in GBLinkController.BoolButtons)
{
if (controller.IsPressed(s))
if (!controller.IsPressed(s)) continue;
CasualPokePlayer marked this conversation as resolved.
Show resolved Hide resolved
if (s[0] is not 'P') continue;
var iSpace = s.IndexOf(' ');
var playerNum = int.Parse(s.Substring(startIndex: 1, length: iSpace - 1));
var consoleNum = 0;
var isSGB = false;
while (consoleNum < _numCores)
{
for (int i = 0; i < _numCores; i++)
{
if (s.Contains($"P{i + 1} "))
{
_linkedConts[i].Set(s.Replace($"P{i + 1} ", ""));
}
}
isSGB = IsSgb(consoleNum);
var playersForConsole = isSGB ? 4 : 1;
if (playerNum <= playersForConsole) break;
playerNum -= playersForConsole;
consoleNum++;
}
//TODO rather than this string manipulation, could construct a lookup ahead of time
_linkedConts[consoleNum].Set(s.EndsWithOrdinal("Power")
? "Power"
: isSGB
? $"P{playerNum} {s.Substring(startIndex: iSpace + 1)}"
: s.Substring(startIndex: iSpace + 1));
}

bool linkDiscoSignalNew = controller.IsPressed("Toggle Link Connection");
Expand Down Expand Up @@ -66,10 +77,11 @@ public bool FrameAdvance(IController controller, bool render, bool rendersound =

unsafe
{
fixed (int* fbuff = &FrameBuffer[0])
fixed (int* fbuff = &FrameBuffer[0], svbuff = SgbVideoBuffer)
{
// use pitch to have both cores write to the same frame buffer, interleaved
int Pitch = 160 * _numCores;
int sgbPitch = 256 * _numCores;

fixed (short* sbuff = &SoundBuffer[0])
{
Expand Down Expand Up @@ -102,6 +114,27 @@ public bool FrameAdvance(IController controller, bool render, bool rendersound =
{
Array.Copy(FrameBuffer, (i * 160) + (j * Pitch), VideoBuffer, (i * 160) + (j * Pitch), 160);
}
if (IsAnySgb)
{
// all SGB borders will be displayed when any of them has the option enabled
if (IsSgb(i))
{
if (LibGambatte.gambatte_updatescreenborder(
_linkedCores[i].GambatteState,
svbuff + (i * 256),
sgbPitch) is not 0)
{
throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_updatescreenborder)}() returned non-zero (border error???)");
}
}
else
{
for (int j = 0; j < 144; j++)
{
Array.Copy(FrameBuffer, (i * 160) + (j * Pitch), SgbVideoBuffer, (i * 256 + 48) + (40 + j) * sgbPitch, 160);
}
}
}
}

n[i] += (int)nsamp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
public partial class GambatteLink : IVideoProvider
{
public int VirtualWidth => 160 * _numCores;
public int VirtualHeight => 144;
public int BufferWidth => 160 * _numCores;
public int BufferHeight => 144;
public int VirtualWidth
=> (ShowAnyBorder() ? 256 : 160) * _numCores;

public int VirtualHeight
=> ShowAnyBorder() ? 224 : 144;

public int BufferWidth
=> VirtualWidth;

public int BufferHeight
=> VirtualHeight;

public int VsyncNumerator => _linkedCores[P1].VsyncNumerator;

Expand All @@ -17,19 +24,24 @@ public partial class GambatteLink : IVideoProvider

private readonly int[] FrameBuffer;

public int[] GetVideoBuffer() => VideoBuffer;
public int[] GetVideoBuffer()
=> ShowAnyBorder() ? SgbVideoBuffer : VideoBuffer;

private readonly int[] VideoBuffer;


private readonly int[] SgbVideoBuffer;

private int[] CreateVideoBuffer()
{
var b = new int[BufferWidth * BufferHeight];
var b = new int[160 * _numCores * 144];
for (int i = 0; i < b.Length; i++)
{
b[i] = -1; // GB/C screen is disabled on bootup, so it always starts as white, not black
}
return b;
}

private int[] CreateSGBVideoBuffer()
=> IsAnySgb ? new int[256 * _numCores * 224] : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public GambatteLink(CoreLoadParameters<GambatteLinkSettings, GambatteLinkSyncSet
_linkedCores[i] = new Gameboy(lp.Comm, lp.Roms[i].Game, lp.Roms[i].RomData, _settings._linkedSettings[i], _syncSettings._linkedSyncSettings[i], lp.DeterministicEmulationRequested);
_linkedCores[i].ConnectInputCallbackSystem(_inputCallbacks);
_linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks, i);
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: false, rumble: false, remote: false));
IsAnySgb |= IsSgb(i);
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(sgb: IsSgb(i), sub: false, tilt: false, rumble: false, remote: false));
_linkedBlips[i] = new BlipBuffer(1024);
_linkedBlips[i].SetRates(2097152 * 2, 44100);
_linkedOverflow[i] = 0;
Expand All @@ -67,6 +68,7 @@ public GambatteLink(CoreLoadParameters<GambatteLinkSettings, GambatteLinkSyncSet

FrameBuffer = CreateVideoBuffer();
VideoBuffer = CreateVideoBuffer();
SgbVideoBuffer = CreateSGBVideoBuffer();

GBLinkController = CreateControllerDefinition();

Expand Down Expand Up @@ -143,12 +145,23 @@ public IGameboyCommon First

private ControllerDefinition CreateControllerDefinition()
{
static void AddGBButtonsForPlayer(int p, ControllerDefinition ret)
{
var pfx = $"P{p} ";
ret.BoolButtons.AddRange(new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" }
.Select(s => pfx + s));
}
ControllerDefinition ret = new($"GB Link {_numCores}x Controller");
for (int i = 0; i < _numCores; i++)
for (int i = 0, p = 1; i < _numCores; i++)
{
ret.BoolButtons.AddRange(
new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start", "Power" }
.Select(s => $"P{i + 1} {s}"));
AddGBButtonsForPlayer(p, ret);
ret.BoolButtons.Add($"P{p} Power");
p++;
if (IsSgb(i))
{
// add 3 more gamepads without a Power button
for (int e = p + 3; p < e; p++) AddGBButtonsForPlayer(p, ret);
}
}
ret.BoolButtons.Add("Toggle Link Connection");
if (_numCores > 2)
Expand All @@ -159,6 +172,20 @@ private ControllerDefinition CreateControllerDefinition()
return ret.MakeImmutable();
}

private bool IsSgb(int i)
=> _linkedCores[i].IsSgb;

public bool IsAnySgb { get; private set; }

private bool ShowBorder(int i)
=> IsSgb(i) && _settings._linkedSettings[i].ShowBorder;

public bool ShowAnyBorder()
{
for (var i = 0; i < _numCores; i++) if (ShowBorder(i)) return true;
return false;
}

private const int P1 = 0;
private const int P2 = 1;
private const int P3 = 2;
Expand Down
Loading