Mac: Cheat entry

This commit is contained in:
Michael Buckley 2022-02-06 15:03:46 -08:00
parent 8685db48a7
commit 6b9f79a9e3
17 changed files with 1377 additions and 486 deletions

View File

@ -15,12 +15,13 @@
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2021 Michael Donald Buckley
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <Cocoa/Cocoa.h>
#import <snes9x_framework/snes9x_framework.h>
#import "S9xPreferences/S9xPreferencesWindowController.h"
#import "Cheats/S9xCheatsViewController.h"
extern NSWindowFrameAutosaveName const kMainWindowIdentifier;
@ -31,6 +32,7 @@ extern NSWindowFrameAutosaveName const kMainWindowIdentifier;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *keys;
@property (nonatomic, strong) NSWindow *gameWindow;
@property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController;
@property (nonatomic, strong) NSWindowController *cheatsWindowController;
@property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting;
- (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player;

View File

@ -15,7 +15,7 @@
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <Carbon/Carbon.h>
@ -23,6 +23,7 @@
#import "S9xPreferencesConstants.h"
NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow";
@implementation AppDelegate
@ -194,6 +195,9 @@ NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
[self importKeySettings];
[self importGraphicsSettings];
[self applyEmulationSettings];
self.s9xEngine.cheatsEnabled = [defaults boolForKey:kEnableCheatsPref];
[defaults synchronize];
}
@ -463,6 +467,11 @@ NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
[s9xView.leftAnchor constraintGreaterThanOrEqualToAnchor:gameWindow.contentView.leftAnchor].active = YES;
[s9xView.rightAnchor constraintLessThanOrEqualToAnchor:gameWindow.contentView.rightAnchor].active = YES;
if (self.cheatsWindowController != nil)
{
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) deselectAll];
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) reloadData];
}
[gameWindow makeKeyAndOrderFront:self];
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:url];
@ -481,6 +490,17 @@ NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
else if (action == @selector(updateDeviceSetting:)) {
menuItem.state = (self.deviceSetting == (S9xDeviceSetting)menuItem.tag) ? NSOnState : NSOffState;
}
else if (action == @selector(toggleCheats:))
{
if (self.s9xEngine.cheatsEnabled)
{
menuItem.title = NSLocalizedString(@"Disable Cheats", nil);
}
else
{
menuItem.title = NSLocalizedString(@"Enable Cheats", nil);
}
}
return !self.isRunningEmulation;
}
@ -587,4 +607,35 @@ NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
}
- (IBAction)openCheatsWindow:(id)sender
{
if (self.cheatsWindowController == nil)
{
NSWindow *window = [NSWindow windowWithContentViewController:[[S9xCheatsViewController alloc] initWithNibName:@"S9xCheatsViewController" bundle:nil]];
self.cheatsWindowController = [[NSWindowController alloc] initWithWindow:window];
window = self.cheatsWindowController.window;
window.title = NSLocalizedString(@"Cheats", nil);
window.restorationClass = self.class;
window.frameAutosaveName = kCheatsWindowIdentifier;
window.releasedWhenClosed = NO;
if ( ![window setFrameUsingName:kCheatsWindowIdentifier] )
{
[window center];
}
}
[self.cheatsWindowController showWindow:nil];
[self.cheatsWindowController.window makeKeyAndOrderFront:nil];
[self.cheatsWindowController.window makeKeyWindow];
}
- (IBAction)toggleCheats:(id)sender
{
self.s9xEngine.cheatsEnabled = !self.s9xEngine.cheatsEnabled;
[NSUserDefaults.standardUserDefaults setBool:self.s9xEngine.cheatsEnabled forKey:kEnableCheatsPref];
}
@end

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16097.3"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -94,6 +95,225 @@
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="hfX-Gc-Rmh">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="d1i-Nq-o0y">
<items>
<menuItem title="Undo" keyEquivalent="z" id="CRw-8g-dqq">
<connections>
<action selector="undo:" target="-1" id="oqy-wX-XcR"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="CdC-5F-VDh">
<connections>
<action selector="redo:" target="-1" id="kJD-Xz-Zty"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="nRT-Cs-jI0"/>
<menuItem title="Cut" keyEquivalent="x" id="U6Z-3p-PPh">
<connections>
<action selector="cut:" target="-1" id="yHv-Hk-RPa"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="5cj-G2-7gk">
<connections>
<action selector="copy:" target="-1" id="6Ld-tc-P6r"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="TeD-Jo-cdQ">
<connections>
<action selector="paste:" target="-1" id="Iux-BI-cfB"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="bjo-AI-m9c">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="GAC-Wa-wBS"/>
</connections>
</menuItem>
<menuItem title="Delete" id="5ri-yU-J0H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="CQu-g4-54R"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="7lE-39-sok">
<connections>
<action selector="selectAll:" target="-1" id="knb-10-R70"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="tAo-56-xcT"/>
<menuItem title="Find" id="zSy-Xx-KQa">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="GEm-kH-bZL">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="uIF-VE-Z6k">
<connections>
<action selector="performFindPanelAction:" target="-1" id="IPt-dD-fAN"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="QtG-Fs-n6K">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="9BN-tN-3DT"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="nnl-za-IbF">
<connections>
<action selector="performFindPanelAction:" target="-1" id="bSc-gk-JuQ"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="qWR-cm-W1V">
<connections>
<action selector="performFindPanelAction:" target="-1" id="tv2-yd-vpb"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="o3Q-m6-FJO">
<connections>
<action selector="performFindPanelAction:" target="-1" id="M9V-9P-thc"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="G0a-qW-Bbf">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="nhp-QW-gWb"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="ZhJ-ys-AG3">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="0bK-KI-BgN">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="Mcv-I1-eIG">
<connections>
<action selector="showGuessPanel:" target="-1" id="clh-Fo-Ijh"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="8OB-ZV-Y89">
<connections>
<action selector="checkSpelling:" target="-1" id="Zsb-I1-m2z"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kmA-62-3BG"/>
<menuItem title="Check Spelling While Typing" id="9uJ-Lj-27Z">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="tbo-iz-xWm"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="7Pr-2A-IZz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="vVM-cJ-76v"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="H8Z-ar-hDG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="DeB-zv-squ"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="Tg6-1Z-oYb">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="nYE-gK-pd5">
<items>
<menuItem title="Show Substitutions" id="sKx-tp-8do">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="hLR-Cc-W4X"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="J6a-TH-0cM"/>
<menuItem title="Smart Copy/Paste" id="6zQ-rA-n4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="L3I-lk-Rc1"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="6gP-bb-GhK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="zIF-Bj-nHr"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="6Kf-xg-whp">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="TVL-NZ-cgx"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="529-ZM-vx1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="6Tb-yQ-xJY"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="auV-3d-GUN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="cXL-of-q81"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="Jg7-Zo-CgX">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="lN5-BH-4vr"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="pMI-ev-WNp">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="1hV-QX-gUc">
<items>
<menuItem title="Make Upper Case" id="3je-Bq-QuL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="n26-tf-uhF"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="Dep-YV-sBp">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="UeC-6R-cAp"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="M87-rn-9bP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="j3f-7O-Fq2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="ycZ-G4-VRG">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="vH3-f7-pA9">
<items>
<menuItem title="Start Speaking" id="n7w-d1-Ucd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="Lp4-Sq-aS1"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="ibA-8o-W5l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="vLl-Od-P5E"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Emulation" id="Kjk-eO-rPI">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Emulation" id="s2F-Pd-YT5">
@ -174,6 +394,25 @@
</items>
</menu>
</menuItem>
<menuItem title="Cheats" id="ee5-dW-h20">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Cheats" id="Bsy-Nq-yAm">
<items>
<menuItem title="Enable Cheats" id="5Gg-4s-ZCo">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleCheats:" target="-1" id="IZg-ZR-9iA"/>
</connections>
</menuItem>
<menuItem title="Show Cheats" id="9oz-Uu-GkA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="openCheatsWindow:" target="-1" id="VdR-bM-JgN"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">

View File

@ -0,0 +1,33 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@class S9xCheatItem;
@interface S9xCheatEditViewController : NSViewController
- (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,150 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatEditViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface S9xCheatEditViewController () <NSTextFieldDelegate>
@property (nonatomic, weak) IBOutlet NSTextField *codeField;
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
@property (nonatomic, weak) IBOutlet NSTextField *invalidCodeLabel;
@property (nonatomic, weak) IBOutlet NSButton *saveButton;
@property (nonatomic, strong) S9xCheatItem *cheatItem;
@property (nonatomic, copy) void (^saveBlock)(void);
@end
@implementation S9xCheatEditViewController
- (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback
{
if (self = [super initWithNibName:@"S9xCheatEditViewController" bundle:nil])
{
_cheatItem = cheatItem;
_saveBlock = saveCallback;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.cheatItem != nil)
{
self.descriptionField.stringValue = self.cheatItem.cheatDescription;
self.addressField.objectValue = self.cheatItem.address;
self.valueField.objectValue = self.cheatItem.value;
}
[self updateSaveButton];
}
- (void)controlTextDidChange:(NSNotification *)notification
{
if (notification.object == self.codeField)
{
if (self.codeField.stringValue.length > 0 )
{
uint32 address = 0;
uint8 value = 0;
if ( CheatValuesFromCode(self.codeField.stringValue, &address, &value) )
{
self.addressField.objectValue = @(address);
self.valueField.objectValue = @(value);
self.invalidCodeLabel.hidden = YES;
}
else
{
self.addressField.stringValue = @"";
self.valueField.stringValue = @"";
self.invalidCodeLabel.hidden = NO;
}
}
else
{
if (self.cheatItem != nil)
{
self.addressField.objectValue = self.cheatItem.address;
self.valueField.objectValue = self.cheatItem.value;
}
else
{
self.addressField.stringValue = @"";
self.valueField.stringValue = @"";
}
self.invalidCodeLabel.hidden = YES;
}
}
else if (notification.object == self.addressField || notification.object == self.valueField)
{
self.codeField.stringValue = @"";
}
[self updateSaveButton];
}
- (void)updateSaveButton
{
self.saveButton.enabled = (self.addressField.stringValue.length > 0 && self.valueField.stringValue.length > 0);
}
- (IBAction)save:(id)sender
{
if ( self.cheatItem != nil )
{
self.cheatItem.address = self.addressField.objectValue;
self.cheatItem.value = self.valueField.objectValue;
self.cheatItem.cheatDescription = self.descriptionField.stringValue;
}
else
{
if (self.codeField.stringValue.length > 0)
{
CreateCheatFromCode(self.codeField.stringValue, self.descriptionField.stringValue);
}
else
{
CreateCheatFromAddress(self.addressField.objectValue, self.valueField.objectValue, self.descriptionField.stringValue);
}
}
[self dismissViewController:self];
self.saveBlock();
}
- (IBAction)cancelOperation:(nullable id)sender
{
[self dismissViewController:self];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="S9xCheatEditViewController">
<connections>
<outlet property="addressField" destination="D6y-BE-IK3" id="d5P-wa-Smp"/>
<outlet property="codeField" destination="0sv-1S-EIB" id="NgH-hC-0w9"/>
<outlet property="descriptionField" destination="nEa-pB-Mzq" id="oxa-VB-Fxd"/>
<outlet property="invalidCodeLabel" destination="KZs-5Q-3p9" id="grc-UN-oat"/>
<outlet property="saveButton" destination="hSd-vC-YVB" id="eXA-qI-8s2"/>
<outlet property="valueField" destination="Dhp-d5-iPA" id="swy-G0-yNz"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="480" height="161"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="GCw-FQ-ML2">
<rect key="frame" x="18" y="125" width="95" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Code:" id="MsD-CX-uiA">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ocx-0r-xce">
<rect key="frame" x="18" y="94" width="95" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Description:" id="qGa-0B-bfl">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0sv-1S-EIB">
<rect key="frame" x="119" y="122" width="341" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="rUK-Hh-f2D">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="skT-dO-kOt"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nEa-pB-Mzq">
<rect key="frame" x="119" y="91" width="341" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="Xx1-4E-gVH">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="Otl-uB-yiJ"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="D6y-BE-IK3">
<rect key="frame" x="119" y="60" width="167" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="dDB-jS-8FL">
<customFormatter key="formatter" id="h5V-Ki-4jN" customClass="S9xAddressFormatter"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="2Hq-IC-08n"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WBj-hA-3op">
<rect key="frame" x="18" y="63" width="95" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Address (Hex):" id="JjJ-Y6-aDd">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="W3i-GO-VrX">
<rect key="frame" x="292" y="63" width="78" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Value (Hex):" id="xcZ-Zz-oEB">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Dhp-d5-iPA">
<rect key="frame" x="376" y="60" width="84" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="zvh-hx-r62">
<customFormatter key="formatter" id="5Nt-dm-EVe" customClass="S9xValueFormatter"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="tcg-Mr-bad"/>
</connections>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hSd-vC-YVB">
<rect key="frame" x="391" y="13" width="76" height="32"/>
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="BeG-Mv-fdl">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="save:" target="-2" id="YtB-HR-yIq"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="D7Q-2q-Pzm">
<rect key="frame" x="317" y="1" width="76" height="56"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="MYe-Fc-BPg">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancelOperation:" target="-2" id="VQ1-m5-QEe"/>
</connections>
</button>
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KZs-5Q-3p9">
<rect key="frame" x="18" y="20" width="96" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Code is invalid." id="afl-tf-lbT">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Dhp-d5-iPA" secondAttribute="trailing" constant="20" symbolic="YES" id="21W-9V-32u"/>
<constraint firstAttribute="bottom" secondItem="KZs-5Q-3p9" secondAttribute="bottom" constant="20" symbolic="YES" id="4HP-HF-AEl"/>
<constraint firstItem="Dhp-d5-iPA" firstAttribute="top" secondItem="nEa-pB-Mzq" secondAttribute="bottom" constant="10" symbolic="YES" id="63A-Ma-OtX"/>
<constraint firstItem="GCw-FQ-ML2" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="8qY-Ac-0CN"/>
<constraint firstItem="nEa-pB-Mzq" firstAttribute="leading" secondItem="ocx-0r-xce" secondAttribute="trailing" constant="8" symbolic="YES" id="9k6-tR-gwZ"/>
<constraint firstItem="GCw-FQ-ML2" firstAttribute="firstBaseline" secondItem="0sv-1S-EIB" secondAttribute="firstBaseline" id="Ac2-1g-SE0"/>
<constraint firstAttribute="bottom" secondItem="hSd-vC-YVB" secondAttribute="bottom" constant="20" symbolic="YES" id="DPN-xe-MNJ"/>
<constraint firstItem="Dhp-d5-iPA" firstAttribute="leading" secondItem="W3i-GO-VrX" secondAttribute="trailing" constant="8" symbolic="YES" id="Fb0-7T-6fc"/>
<constraint firstItem="D7Q-2q-Pzm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="KZs-5Q-3p9" secondAttribute="trailing" constant="8" symbolic="YES" id="G6I-4t-cuH"/>
<constraint firstAttribute="trailing" secondItem="0sv-1S-EIB" secondAttribute="trailing" constant="20" symbolic="YES" id="IwN-oX-xyo"/>
<constraint firstItem="ocx-0r-xce" firstAttribute="trailing" secondItem="GCw-FQ-ML2" secondAttribute="trailing" id="JBV-A1-7IM"/>
<constraint firstItem="D7Q-2q-Pzm" firstAttribute="width" secondItem="hSd-vC-YVB" secondAttribute="width" id="JPv-Je-6IC"/>
<constraint firstItem="D6y-BE-IK3" firstAttribute="leading" secondItem="WBj-hA-3op" secondAttribute="trailing" constant="8" symbolic="YES" id="Jdf-zp-HN9"/>
<constraint firstAttribute="trailing" secondItem="nEa-pB-Mzq" secondAttribute="trailing" constant="20" symbolic="YES" id="MHZ-MZ-8lM"/>
<constraint firstItem="KZs-5Q-3p9" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="MrD-kz-LlV"/>
<constraint firstAttribute="trailing" secondItem="hSd-vC-YVB" secondAttribute="trailing" constant="20" symbolic="YES" id="P79-Hp-Ies"/>
<constraint firstItem="W3i-GO-VrX" firstAttribute="firstBaseline" secondItem="Dhp-d5-iPA" secondAttribute="firstBaseline" id="U8n-RJ-aA2"/>
<constraint firstItem="0sv-1S-EIB" firstAttribute="leading" secondItem="GCw-FQ-ML2" secondAttribute="trailing" constant="8" symbolic="YES" id="YjZ-qJ-VXK"/>
<constraint firstItem="WBj-hA-3op" firstAttribute="trailing" secondItem="ocx-0r-xce" secondAttribute="trailing" id="cEn-lY-sMy"/>
<constraint firstItem="D7Q-2q-Pzm" firstAttribute="top" secondItem="Dhp-d5-iPA" secondAttribute="bottom" constant="8" symbolic="YES" id="dVU-1H-i8D"/>
<constraint firstItem="ocx-0r-xce" firstAttribute="firstBaseline" secondItem="nEa-pB-Mzq" secondAttribute="firstBaseline" id="izn-Ex-sfI"/>
<constraint firstItem="hSd-vC-YVB" firstAttribute="leading" secondItem="D7Q-2q-Pzm" secondAttribute="trailing" constant="12" symbolic="YES" id="jCl-Gz-4aW"/>
<constraint firstItem="ocx-0r-xce" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="ldp-5m-ybj"/>
<constraint firstItem="W3i-GO-VrX" firstAttribute="leading" secondItem="D6y-BE-IK3" secondAttribute="trailing" constant="8" symbolic="YES" id="lgL-8G-EGj"/>
<constraint firstItem="nEa-pB-Mzq" firstAttribute="top" secondItem="0sv-1S-EIB" secondAttribute="bottom" constant="10" symbolic="YES" id="omD-qz-g1p"/>
<constraint firstItem="hSd-vC-YVB" firstAttribute="top" secondItem="Dhp-d5-iPA" secondAttribute="bottom" constant="20" id="qJd-d3-538"/>
<constraint firstItem="D7Q-2q-Pzm" firstAttribute="centerY" secondItem="hSd-vC-YVB" secondAttribute="centerY" id="rvp-aK-XTi"/>
<constraint firstItem="WBj-hA-3op" firstAttribute="firstBaseline" secondItem="D6y-BE-IK3" secondAttribute="firstBaseline" id="vGc-Td-vr8"/>
<constraint firstItem="D6y-BE-IK3" firstAttribute="top" secondItem="nEa-pB-Mzq" secondAttribute="bottom" constant="10" symbolic="YES" id="vR3-eW-lq8"/>
<constraint firstItem="D6y-BE-IK3" firstAttribute="width" secondItem="Dhp-d5-iPA" secondAttribute="width" multiplier="2" id="wAO-sa-aRw"/>
<constraint firstItem="WBj-hA-3op" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="wEF-3Q-1FL"/>
<constraint firstItem="GCw-FQ-ML2" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="yb8-0y-zZn"/>
</constraints>
<point key="canvasLocation" x="140" y="101.5"/>
</customView>
</objects>
</document>

View File

@ -0,0 +1,30 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface S9xCheatsViewController : NSViewController
- (void)deselectAll;
- (void)reloadData;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,266 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatsViewController.h"
#import "S9xCheatEditViewController.h"
@interface S9xCheatsViewController () <NSTableViewDataSource, NSTableViewDelegate>
@property (nonatomic, weak) IBOutlet NSTableView *tableView;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *segmentedControl;
@property (nonatomic, strong) NSArray<S9xCheatItem *> *cheats;
@end
@implementation S9xCheatsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.segmentedControl setEnabled:YES forSegment:0];
[self.segmentedControl setEnabled:NO forSegment:1];
[self.segmentedControl setEnabled:NO forSegment:2];
self.tableView.doubleAction = @selector(editSelectedCheat);
self.tableView.target = self;
[self reloadData];
}
- (void)deselectAll
{
[self.tableView deselectAll:nil];
}
- (void)reloadData
{
NSSet<NSNumber *> *selectedIDs = [NSSet setWithArray:[[self.cheats objectsAtIndexes:self.tableView.selectedRowIndexes] valueForKey:@"cheatID"]];
CGPoint scrollPosition = self.tableView.visibleRect.origin;
self.cheats = [GetAllCheats() sortedArrayUsingDescriptors:self.tableView.sortDescriptors];
[self.tableView reloadData];
NSMutableIndexSet *indexSet = [NSMutableIndexSet new];
for (NSUInteger i = 0; i < self.tableView.numberOfRows; ++i)
{
if ([selectedIDs containsObject:@(self.cheats[i].cheatID)])
{
[indexSet addIndex:i];
}
}
[self.tableView scrollPoint:scrollPosition];
[self.tableView selectRowIndexes:indexSet byExtendingSelection:NO];
}
- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors
{
[self reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return self.cheats.count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSTableCellView *view = [self.tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
view.objectValue = self.cheats[row];
return view;
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
[self.segmentedControl setEnabled:self.tableView.selectedRowIndexes.count > 0 forSegment:1];
[self.segmentedControl setEnabled:self.tableView.selectedRowIndexes.count == 1 forSegment:2];
}
- (IBAction)segmentedControlAction:(NSSegmentedControl *)sender
{
switch(sender.selectedSegment)
{
case 0:
[self addNewCheat];
break;
case 1:
[self deleteSelectedCheats];
break;
case 2:
[self editSelectedCheat];
break;
}
}
- (void)addNewCheat
{
S9xCheatEditViewController *vc = [[S9xCheatEditViewController alloc] initWithCheatItem:nil saveCallback:^
{
[self reloadData];
}];
[self presentViewControllerAsSheet:vc];
}
- (void)deleteSelectedCheats
{
NSIndexSet *selectedRows = self.tableView.selectedRowIndexes;
if (selectedRows.count > 0)
{
NSArray *cheatsToDelete = [[self.cheats objectsAtIndexes:selectedRows] sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"cheatID" ascending:NO]]];
for (S9xCheatItem *item in cheatsToDelete)
{
[item delete];
}
}
[self.tableView deselectAll:self];
[self reloadData];
}
- (void)editSelectedCheat
{
NSIndexSet *selectedRows = self.tableView.selectedRowIndexes;
if (selectedRows.count == 1)
{
S9xCheatItem *item = self.cheats[selectedRows.firstIndex];
S9xCheatEditViewController *vc = [[S9xCheatEditViewController alloc] initWithCheatItem:item saveCallback:^
{
[self reloadData];
}];
[self presentViewControllerAsSheet:vc];
}
}
@end
@interface S9xHexNumberFormatter : NSFormatter
@end
@implementation S9xHexNumberFormatter
+ (NSUInteger)maxLength
{
return NSUIntegerMax;
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error
{
if (string.length > 0)
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
*obj = @(value);
return YES;
}
return NO;
}
- (NSNumber *)numberFromString:(NSString *)string
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
return @(value);
}
- (NSString *)stringForObjectValue:(id)obj
{
if ([obj isKindOfClass:NSNumber.class])
{
return [NSString stringWithFormat:@"%X", ((NSNumber *)obj).unsignedIntValue];
}
else if ([obj isKindOfClass:NSString.class])
{
return obj;
}
return @"";
}
- (BOOL)isPartialStringValid:(NSString * _Nonnull * _Nonnull)partialStringPtr proposedSelectedRange:(nullable NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString * _Nullable * _Nullable)error
{
static NSCharacterSet *hexCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
hexCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"] invertedSet];
});
if ( [*partialStringPtr rangeOfCharacterFromSet:hexCharacterSet].location != NSNotFound )
{
*partialStringPtr = nil;
return NO;
}
*partialStringPtr = (*partialStringPtr).uppercaseString;
if ( (*partialStringPtr).length > self.class.maxLength )
{
*partialStringPtr = [*partialStringPtr substringToIndex:self.class.maxLength];
return NO;
}
return YES;
}
@end
@interface S9xAddressFormatter : S9xHexNumberFormatter
@end
@implementation S9xAddressFormatter
+ (NSUInteger)maxLength
{
return 6;
}
@end
@interface S9xValueFormatter : S9xHexNumberFormatter
@end
@implementation S9xValueFormatter
+ (NSUInteger)maxLength
{
return 2;
}
@end

View File

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="S9xCheatsViewController">
<connections>
<outlet property="segmentedControl" destination="KjP-h3-jKc" id="Bt4-rc-1xy"/>
<outlet property="tableView" destination="pGm-DH-gAd" id="ajm-xs-Jfs"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="540" height="369"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vFP-V1-oDR">
<rect key="frame" x="20" y="49" width="500" height="300"/>
<clipView key="contentView" id="W9Q-F6-649">
<rect key="frame" x="1" y="1" width="498" height="298"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" headerView="Mok-FY-WnT" viewBased="YES" id="pGm-DH-gAd">
<rect key="frame" x="0.0" y="0.0" width="505" height="270"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="EnabledView" width="20" minWidth="20" maxWidth="1000" id="cC0-lr-AA9">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="1Q4-Vz-lfX">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="enabled"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="EnabledView" id="Ut8-IY-g7e">
<rect key="frame" x="8" y="0.0" width="18" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mUE-de-1Om">
<rect key="frame" x="0.0" y="3" width="18" height="18"/>
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="rPf-Je-vka">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="Ut8-IY-g7e" name="value" keyPath="objectValue.enabled" id="ssD-Mp-PzQ"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="mUE-de-1Om" firstAttribute="leading" secondItem="Ut8-IY-g7e" secondAttribute="leading" constant="2" id="9IH-oE-Wmh"/>
<constraint firstAttribute="trailing" secondItem="mUE-de-1Om" secondAttribute="trailing" constant="2" id="BtE-A8-6pc"/>
<constraint firstItem="mUE-de-1Om" firstAttribute="top" secondItem="Ut8-IY-g7e" secondAttribute="top" constant="5" id="ErO-uP-PnI"/>
<constraint firstAttribute="bottom" secondItem="mUE-de-1Om" secondAttribute="bottom" constant="5" id="dkw-y0-pbo"/>
</constraints>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="AddressView" width="70" minWidth="40" maxWidth="1000" id="6PK-fF-GEp">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Address">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Os8-ci-czY">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="address"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="AddressView" id="n6t-oy-t7z">
<rect key="frame" x="43" y="0.0" width="70" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="C4e-ke-M8L">
<rect key="frame" x="0.0" y="4" width="4" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" id="J15-ri-abw">
<customFormatter key="formatter" id="Ufa-zW-hvg" customClass="S9xAddressFormatter"/>
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="n6t-oy-t7z" name="value" keyPath="objectValue.address" id="J5m-Hv-eBy"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="C4e-ke-M8L" secondAttribute="bottom" constant="4" id="Qbc-Zs-F2E"/>
<constraint firstItem="C4e-ke-M8L" firstAttribute="top" secondItem="n6t-oy-t7z" secondAttribute="top" constant="4" id="VUK-22-7nl"/>
<constraint firstItem="C4e-ke-M8L" firstAttribute="leading" secondItem="n6t-oy-t7z" secondAttribute="leading" constant="2" id="ee1-LL-m6k"/>
</constraints>
<connections>
<outlet property="textField" destination="C4e-ke-M8L" id="RY8-UH-zpf"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="ValueView" width="42" minWidth="10" maxWidth="3.4028234663852886e+38" id="da7-KY-Srx">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Value">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="orR-4T-Np6">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="value"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="ValueView" id="fpL-E3-Qdj">
<rect key="frame" x="130" y="0.0" width="42" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="mo4-7p-pED">
<rect key="frame" x="0.0" y="-3" width="42" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" id="1j5-js-5aw">
<customFormatter key="formatter" id="CGB-sD-2m4" customClass="S9xValueFormatter"/>
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="fpL-E3-Qdj" name="value" keyPath="objectValue.value" id="bVa-Le-aZs"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="mo4-7p-pED" secondAttribute="trailing" constant="2" id="0N3-q3-LaN"/>
<constraint firstItem="mo4-7p-pED" firstAttribute="leading" secondItem="fpL-E3-Qdj" secondAttribute="leading" constant="2" id="6ng-aJ-Fes"/>
<constraint firstItem="mo4-7p-pED" firstAttribute="top" secondItem="fpL-E3-Qdj" secondAttribute="top" constant="4" id="fkT-dL-tWB"/>
</constraints>
<connections>
<outlet property="textField" destination="mo4-7p-pED" id="74M-Dw-j3G"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="DescriptionView" width="310" minWidth="10" maxWidth="3.4028234663852886e+38" id="xr9-0R-rR5">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Description">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="Gyh-cB-AzL">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="description"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="DescriptionView" id="cgm-Sc-PIV">
<rect key="frame" x="189" y="0.0" width="307" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Zqt-oO-fx4">
<rect key="frame" x="0.0" y="-3" width="289" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Table View Cell" id="UIU-WQ-1xK">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="cgm-Sc-PIV" name="value" keyPath="objectValue.cheatDescription" id="b05-vX-fT6"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="Zqt-oO-fx4" firstAttribute="top" secondItem="cgm-Sc-PIV" secondAttribute="top" constant="4" id="eqE-l5-rlz"/>
<constraint firstItem="Zqt-oO-fx4" firstAttribute="leading" secondItem="cgm-Sc-PIV" secondAttribute="leading" constant="2" id="n3o-YT-L8Q"/>
<constraint firstAttribute="trailing" secondItem="Zqt-oO-fx4" secondAttribute="trailing" constant="20" symbolic="YES" id="sqE-Bc-4i5"/>
</constraints>
<connections>
<outlet property="textField" destination="Zqt-oO-fx4" id="ny1-SA-vLX"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="DKU-ha-EyO"/>
<outlet property="delegate" destination="-2" id="IXr-Op-DSZ"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="300" id="2Zw-DZ-iMB"/>
<constraint firstAttribute="width" constant="500" id="hrh-eQ-Siq"/>
</constraints>
<scroller key="horizontalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="8UU-uM-WYf">
<rect key="frame" x="1" y="283" width="498" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="N3O-e7-I8W">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="Mok-FY-WnT">
<rect key="frame" x="0.0" y="0.0" width="505" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KjP-h3-jKc">
<rect key="frame" x="20" y="19" width="92" height="23"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="smallSquare" trackingMode="momentary" id="ID9-7o-zKN">
<font key="font" metaFont="system"/>
<segments>
<segment toolTip="Add" image="NSAddTemplate" width="21"/>
<segment toolTip="Remove" image="NSRemoveTemplate" width="21" tag="1"/>
<segment label="Edit" toolTip="Edit" width="42"/>
</segments>
</segmentedCell>
<connections>
<action selector="segmentedControlAction:" target="-2" id="4O4-uP-ch7"/>
</connections>
</segmentedControl>
</subviews>
<constraints>
<constraint firstItem="vFP-V1-oDR" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="0eo-dm-pUd"/>
<constraint firstItem="KjP-h3-jKc" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="7kU-fr-tCu"/>
<constraint firstItem="KjP-h3-jKc" firstAttribute="top" secondItem="vFP-V1-oDR" secondAttribute="bottom" constant="8" symbolic="YES" id="9DQ-M4-0ND"/>
<constraint firstItem="vFP-V1-oDR" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="Zcq-Qu-Aq3"/>
<constraint firstAttribute="trailing" secondItem="vFP-V1-oDR" secondAttribute="trailing" constant="20" symbolic="YES" id="dBe-ee-mae"/>
<constraint firstAttribute="bottom" secondItem="KjP-h3-jKc" secondAttribute="bottom" constant="20" symbolic="YES" id="uIa-MN-siZ"/>
</constraints>
<point key="canvasLocation" x="236" y="188.5"/>
</customView>
</objects>
<resources>
<image name="NSAddTemplate" width="15" height="13"/>
<image name="NSRemoveTemplate" width="15" height="4"/>
</resources>
</document>

View File

@ -38,4 +38,6 @@ extern NSString * const kAllowInvalidVRAMAccessPref;
extern NSString * const kSeparateEchoBufferFromRAMPref;
extern NSString * const kDisableSpriteLimitPref;
extern NSString * const kEnableCheatsPref;
NS_ASSUME_NONNULL_END

View File

@ -35,3 +35,5 @@ NSString * const kApplyGameSpecificHacksPref = @"ApplyGameSpecificHacks";
NSString * const kAllowInvalidVRAMAccessPref = @"AllowInvalidVRAMAccess";
NSString * const kSeparateEchoBufferFromRAMPref = @"SeparateEchoBufferFromRAM";
NSString * const kDisableSpriteLimitPref = @"DisableSpriteLimit";
NSString * const kEnableCheatsPref = @"EnableCheats";

View File

@ -15,13 +15,34 @@
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
#ifndef _mac_cheat_h_
#define _mac_cheat_h_
void ConfigureCheat (void);
#import <Foundation/Foundation.h>
@interface S9xCheatItem : NSView
@property (nonatomic, assign) uint32 cheatID;
@property (nonatomic, strong) NSNumber *address;
@property (nonatomic, strong) NSNumber *value;
@property (nonatomic, strong) NSNumber *enabled;
@property (nonatomic, strong) NSString *cheatDescription;
- (void)delete;
@end
#ifdef __cplusplus
extern "C" {
#endif
bool CheatValuesFromCode(NSString *code, uint32 *address, uint8 *value);
void CreateCheatFromAddress(NSNumber *address, NSNumber *value, NSString *cheatDescription);
void CreateCheatFromCode(NSString *code, NSString *cheatDescription);
NSArray<S9xCheatItem *> *GetAllCheats(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -15,7 +15,7 @@
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley
(c) Copyright 2019 - 2022 Michael Donald Buckley
***********************************************************************************/
@ -42,510 +42,137 @@
extern SCheatData Cheat;
typedef struct
@implementation S9xCheatItem
- (void)setAddress:(uint32)address value:(uint8)value cheatDescription:(const char *)cheatDescription
{
uint32 id;
uint32 address;
uint8 value;
bool8 valid;
bool8 enabled;
char description[22];
} CheatItem;
bool enabled = self.enabled.boolValue;
static WindowRef wRef;
static HIViewRef dbRef;
static CheatItem citem[MAC_MAX_CHEATS];
static uint32 numofcheats;
char code[256];
sprintf(code, "%x=%x", address, value);
S9xModifyCheatGroup(self.cheatID, cheatDescription, code);
static void InitCheatItems (void);
static void ImportCheatItems (void);
static void DetachCheatItems (void);
static void AddCheatItem (void);
static void DeleteCheatItem (void);
static void EnableAllCheatItems (void);
static void DBItemNotificationCallBack (HIViewRef, DataBrowserItemID, DataBrowserItemNotification);
static OSStatus CheatEventHandler (EventHandlerCallRef, EventRef, void *);
static void InitCheatItems (void)
if (enabled)
{
for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
{
citem[i].id = i + 1;
citem[i].valid = false;
citem[i].enabled = false;
citem[i].address = 0;
citem[i].value = 0;
sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
S9xEnableCheatGroup(self.cheatID);
}
}
static void ImportCheatItems (void)
@dynamic address;
- (NSNumber *)address
{
int cheat_num = std::min((int)Cheat.g.size(), MAC_MAX_CHEATS);
for (unsigned int i = 0; i < cheat_num; i++)
return @(Cheat.g[self.cheatID].c[0].address);
}
- (void)setAddress:(NSNumber *)address
{
citem[i].valid = true;
citem[i].enabled = Cheat.g[i].enabled;
citem[i].address = Cheat.g[i].c[0].address; // mac dialog only supports one cheat per group at the moment
citem[i].value = Cheat.g[i].c[0].byte;
strncpy(citem[i].description, Cheat.g[i].name, 21);
citem[i].description[21] = '\0';
[self setAddress:address.unsignedIntValue value:Cheat.g[self.cheatID].c[0].byte cheatDescription:self.cheatDescription.UTF8String];
}
@dynamic value;
- (NSNumber *)value
{
return @(Cheat.g[self.cheatID].c[0].byte);
}
- (void)setValue:(NSNumber *)value
{
[self setAddress:Cheat.g[self.cheatID].c[0].address value:value.unsignedCharValue cheatDescription:self.cheatDescription.UTF8String];
}
@dynamic enabled;
- (NSNumber *)enabled
{
return @(Cheat.g[self.cheatID].enabled);
}
- (void)setEnabled:(NSNumber *)enabled
{
if (enabled.boolValue)
{
S9xEnableCheatGroup(self.cheatID);
}
else
{
S9xDisableCheatGroup(self.cheatID);
}
}
static void DetachCheatItems (void)
@dynamic cheatDescription;
- (NSString *)cheatDescription
{
S9xDeleteCheats();
for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
{
if (citem[i].valid)
{
char code[10];
snprintf(code, 10, "%x=%x", citem[i].address, citem[i].value);
int index = S9xAddCheatGroup(citem[i].description, code);
if(citem[i].enabled && index >= 0)
S9xEnableCheatGroup(index);
}
}
return [NSString stringWithUTF8String:Cheat.g[self.cheatID].name];
}
void ConfigureCheat (void)
- (void)setCheatDescription:(NSString *)cheatDescription
{
if (!cartOpen)
return;
// OSStatus err;
// IBNibRef nibRef;
//
// err = CreateNibReference(kMacS9XCFString, &nibRef);
// if (err == noErr)
// {
// err = CreateWindowFromNib(nibRef, CFSTR("CheatEntry"), &wRef);
// if (err == noErr)
// {
// DataBrowserCallbacks callbacks;
// EventHandlerRef eref;
// EventHandlerUPP eUPP;
// EventTypeSpec events[] = { { kEventClassCommand, kEventCommandProcess },
// { kEventClassCommand, kEventCommandUpdateStatus },
// { kEventClassWindow, kEventWindowClose } };
// HIViewRef ctl, root;
// HIViewID cid;
//
// root = HIViewGetRoot(wRef);
// cid.id = 0;
// cid.signature = kDataBrowser;
// HIViewFindByID(root, cid, &dbRef);
//
// #ifdef MAC_PANTHER_SUPPORT
// if (systemVersion < 0x1040)
// {
// HISize minSize;
// Rect rct;
//
// GetWindowBounds(wRef, kWindowContentRgn, &rct);
// minSize.width = (float) (rct.right - rct.left);
// minSize.height = (float) (rct.bottom - rct.top );
// err = SetWindowResizeLimits(wRef, &minSize, NULL);
// }
// #endif
//
// callbacks.version = kDataBrowserLatestCallbacks;
// err = InitDataBrowserCallbacks(&callbacks);
// callbacks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP(DBClientDataCallback);
// callbacks.u.v1.itemCompareCallback = NewDataBrowserItemCompareUPP(DBCompareCallBack);
// callbacks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP(DBItemNotificationCallBack);
// err = SetDataBrowserCallbacks(dbRef, &callbacks);
//
// if (systemVersion >= 0x1040)
// err = DataBrowserChangeAttributes(dbRef, kDataBrowserAttributeListViewAlternatingRowColors, kDataBrowserAttributeNone);
//
// InitCheatItems();
// ImportCheatItems();
//
// DataBrowserItemID *id;
//
// id = new DataBrowserItemID[MAC_MAX_CHEATS];
// if (!id)
// QuitWithFatalError(@"cheat 01");
//
// numofcheats = 0;
//
// for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
// {
// if (citem[i].valid)
// {
// id[numofcheats] = citem[i].id;
// numofcheats++;
// }
// }
//
// if (numofcheats)
// err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, numofcheats, id, kDataBrowserItemNoProperty);
//
// delete [] id;
//
// cid.signature = kNewButton;
// HIViewFindByID(root, cid, &ctl);
// if (numofcheats == MAC_MAX_CHEATS)
// err = DeactivateControl(ctl);
// else
// err = ActivateControl(ctl);
//
// cid.signature = kAllButton;
// HIViewFindByID(root, cid, &ctl);
// if (numofcheats == 0)
// err = DeactivateControl(ctl);
// else
// err = ActivateControl(ctl);
//
// cid.signature = kDelButton;
// HIViewFindByID(root, cid, &ctl);
// err = DeactivateControl(ctl);
//
// eUPP = NewEventHandlerUPP(CheatEventHandler);
// err = InstallWindowEventHandler(wRef, eUPP, GetEventTypeCount(events), events, (void *) wRef, &eref);
//
// err = SetKeyboardFocus(wRef, dbRef, kControlFocusNextPart);
//
// MoveWindowPosition(wRef, kWindowCheatEntry, true);
// ShowWindow(wRef);
// err = RunAppModalLoopForWindow(wRef);
// HideWindow(wRef);
// SaveWindowPosition(wRef, kWindowCheatEntry);
//
// err = RemoveEventHandler(eref);
// DisposeEventHandlerUPP(eUPP);
//
// DisposeDataBrowserItemNotificationUPP(callbacks.u.v1.itemNotificationCallback);
// DisposeDataBrowserItemCompareUPP(callbacks.u.v1.itemCompareCallback);
// DisposeDataBrowserItemDataUPP(callbacks.u.v1.itemDataCallback);
//
// CFRelease(wRef);
//
// DetachCheatItems();
// }
//
// DisposeNibReference(nibRef);
// }
[self setAddress:Cheat.g[self.cheatID].c[0].address value:Cheat.g[self.cheatID].c[0].byte cheatDescription:cheatDescription.UTF8String];
}
static void AddCheatItem (void)
- (void)delete
{
// OSStatus err;
// HIViewRef ctl, root;
// HIViewID cid;
// DataBrowserItemID id[1];
// unsigned int i;
//
// if (numofcheats == MAC_MAX_CHEATS)
// return;
//
// for (i = 0; i < MAC_MAX_CHEATS; i++)
// if (citem[i].valid == false)
// break;
//
// if (i == MAC_MAX_CHEATS)
// return;
//
// numofcheats++;
// citem[i].valid = true;
// citem[i].enabled = false;
// citem[i].address = 0;
// citem[i].value = 0;
// sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
//
// id[0] = citem[i].id;
// err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty);
// err = RevealDataBrowserItem(dbRef, id[0], kCmAddress, true);
//
// root = HIViewGetRoot(wRef);
// cid.id = 0;
//
// if (numofcheats == MAC_MAX_CHEATS)
// {
// cid.signature = kNewButton;
// HIViewFindByID(root, cid, &ctl);
// err = DeactivateControl(ctl);
// }
//
// if (numofcheats)
// {
// cid.signature = kAllButton;
// HIViewFindByID(root, cid, &ctl);
// err = ActivateControl(ctl);
// }
S9xDeleteCheatGroup(self.cheatID);
}
static void DeleteCheatItem (void)
@end
extern "C"
{
// OSStatus err;
// HIViewRef ctl, root;
// HIViewID cid;
// Handle selectedItems;
// ItemCount selectionCount;
//
// selectedItems = NewHandle(0);
// if (!selectedItems)
// return;
//
// err = GetDataBrowserItems(dbRef, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, selectedItems);
// selectionCount = (GetHandleSize(selectedItems) / sizeof(DataBrowserItemID));
//
// if (selectionCount == 0)
// {
// DisposeHandle(selectedItems);
// return;
// }
//
// err = RemoveDataBrowserItems(dbRef, kDataBrowserNoItem, selectionCount, (DataBrowserItemID *) *selectedItems, kDataBrowserItemNoProperty);
//
// for (unsigned int i = 0; i < selectionCount; i++)
// {
// citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].valid = false;
// citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].enabled = false;
// numofcheats--;
// }
//
// DisposeHandle(selectedItems);
//
// root = HIViewGetRoot(wRef);
// cid.id = 0;
//
// if (numofcheats < MAC_MAX_CHEATS)
// {
// cid.signature = kNewButton;
// HIViewFindByID(root, cid, &ctl);
// err = ActivateControl(ctl);
// }
//
// if (numofcheats == 0)
// {
// cid.signature = kAllButton;
// HIViewFindByID(root, cid, &ctl);
// err = DeactivateControl(ctl);
// }
bool CheatValuesFromCode(NSString *code, uint32 *address, uint8 *value)
{
const char *text = code.UTF8String;
if (!S9xGameGenieToRaw (text, *address, *value))
{
return true;
}
static void EnableAllCheatItems (void)
if (!S9xProActionReplayToRaw (text, *address, *value))
{
// OSStatus err;
//
// for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
// if (citem[i].valid)
// citem[i].enabled = true;
//
// err = UpdateDataBrowserItems(dbRef, kDataBrowserNoItem, kDataBrowserNoItem, NULL, kDataBrowserItemNoProperty, kCmCheckBox);
return true;
}
static OSStatus DBClientDataCallback (HIViewRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue)
else if (sscanf (text, "%x = %x", (unsigned int *)address, (unsigned int *)value) == 2)
{
// OSStatus err, result;
// CFStringRef str;
// Boolean r;
// uint32 address;
// uint8 value;
// char code[256];
//
// result = noErr;
//
// switch (property)
// {
// case kCmCheckBox:
// ThemeButtonValue buttonValue;
//
// if (changeValue)
// {
// err = GetDataBrowserItemDataButtonValue(itemData, &buttonValue);
// citem[itemID - 1].enabled = (buttonValue == kThemeButtonOn) ? true : false;
// }
// else
// err = SetDataBrowserItemDataButtonValue(itemData, citem[itemID - 1].enabled ? kThemeButtonOn : kThemeButtonOff);
//
// break;
//
// case kCmAddress:
// if (changeValue)
// {
// err = GetDataBrowserItemDataText(itemData, &str);
// r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
// CFRelease(str);
// if (r)
// {
// Boolean translated;
//
// if (S9xProActionReplayToRaw(code, address, value) == NULL)
// translated = true;
// else
// if (S9xGameGenieToRaw(code, address, value) == NULL)
// translated = true;
// else
// {
// translated = false;
// if (sscanf(code, "%" SCNx32, &address) != 1)
// address = 0;
// else
// address &= 0xFFFFFF;
// }
//
// citem[itemID - 1].address = address;
// sprintf(code, "%06" PRIX32, address);
// str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
// err = SetDataBrowserItemDataText(itemData, str);
// CFRelease(str);
//
// if (translated)
// {
// DataBrowserItemID id[1];
//
// citem[itemID - 1].value = value;
// id[0] = itemID;
// err = UpdateDataBrowserItems(browser, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty, kCmValue);
// }
// }
// }
// else
// {
// sprintf(code, "%06" PRIX32, citem[itemID - 1].address);
// str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
// err = SetDataBrowserItemDataText(itemData, str);
// CFRelease(str);
// }
//
// break;
//
// case kCmValue:
// if (changeValue)
// {
// err = GetDataBrowserItemDataText(itemData, &str);
// r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
// CFRelease(str);
// if (r)
// {
// uint32 byte;
//
// if (sscanf(code, "%" SCNx32, &byte) == 1)
// citem[itemID - 1].value = (uint8) byte;
// else
// {
// citem[itemID - 1].value = 0;
// err = SetDataBrowserItemDataText(itemData, CFSTR("00"));
// }
// }
// }
// else
// {
// sprintf(code, "%02" PRIX8, citem[itemID - 1].value);
// str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
// err = SetDataBrowserItemDataText(itemData, str);
// CFRelease(str);
// }
//
// break;
//
// case kCmDescription:
// if (changeValue)
// {
// code[0] = 0;
// err = GetDataBrowserItemDataText(itemData, &str);
// strcpy(code, GetMultiByteCharacters(str, 19));
// CFRelease(str);
//
// if (code[0] == 0)
// {
// code[0] = ' ';
// code[1] = 0;
// }
//
// strcpy(citem[itemID - 1].description, code);
// }
// else
// {
// str = CFStringCreateWithCString(kCFAllocatorDefault, citem[itemID - 1].description, CFStringGetSystemEncoding());
// err = SetDataBrowserItemDataText(itemData, str);
// CFRelease(str);
// }
//
// break;
//
// case kDataBrowserItemIsActiveProperty:
// err = SetDataBrowserItemDataBooleanValue(itemData, true);
// break;
//
// case kDataBrowserItemIsEditableProperty:
// err = SetDataBrowserItemDataBooleanValue(itemData, true);
// break;
//
// default:
// result = errDataBrowserPropertyNotSupported;
// }
//
// return (result);
return 0;
return true;
}
static OSStatus CheatEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
else if (sscanf (text, "%x / %x", (unsigned int *)address, (unsigned int *)value) == 2)
{
// OSStatus err, result = eventNotHandledErr;
// WindowRef tWindowRef;
//
// tWindowRef = (WindowRef) inUserData;
//
// switch (GetEventClass(inEvent))
// {
// case kEventClassWindow:
// switch (GetEventKind(inEvent))
// {
// case kEventWindowClose:
// QuitAppModalLoopForWindow(tWindowRef);
// result = noErr;
// break;
// }
//
// break;
//
// case kEventClassCommand:
// switch (GetEventKind(inEvent))
// {
// HICommand tHICommand;
//
// case kEventCommandUpdateStatus:
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
// if (err == noErr && tHICommand.commandID == 'clos')
// {
// UpdateMenuCommandStatus(true);
// result = noErr;
// }
//
// break;
//
// case kEventCommandProcess:
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
// if (err == noErr)
// {
// switch (tHICommand.commandID)
// {
// case kNewButton:
// AddCheatItem();
// result = noErr;
// break;
//
// case kDelButton:
// DeleteCheatItem();
// result = noErr;
// break;
//
// case kAllButton:
// EnableAllCheatItems();
// result = noErr;
// }
// }
// }
// }
//
// return (result);
return 0;
return true;
}
return false;
}
void CreateCheatFromAddress(NSNumber *address, NSNumber *value, NSString *cheatDescription)
{
char code[256];
sprintf(code, "%x=%x", address.unsignedIntValue, value.unsignedCharValue);
S9xAddCheatGroup(cheatDescription.UTF8String, code);
S9xEnableCheatGroup(Cheat.g.size() - 1);
}
void CreateCheatFromCode(NSString *code, NSString *cheatDescription)
{
S9xAddCheatGroup(cheatDescription.UTF8String, code.UTF8String);
S9xEnableCheatGroup(Cheat.g.size() - 1);
}
NSArray<S9xCheatItem *> *GetAllCheats(void)
{
NSMutableArray *cheats = [NSMutableArray new];
uint32 cheatID = 0;
for (auto it : Cheat.g)
{
S9xCheatItem *cheat = [S9xCheatItem new];
cheat.cheatID = cheatID++;
[cheats addObject:cheat];
}
return cheats;
}
}

View File

@ -177,6 +177,8 @@ extern id<S9xInputDelegate> inputDelegate;
@property (nonatomic, weak) id<S9xInputDelegate> inputDelegate;
@property (nonatomic, assign) BOOL cheatsEnabled;
- (void)recreateS9xView;
- (void)start;

View File

@ -3409,6 +3409,17 @@ void QuitWithFatalError ( NSString *message)
return inputDelegate;
}
@dynamic cheatsEnabled;
- (BOOL)cheatsEnabled
{
return Cheat.enabled;
}
- (void)setCheatsEnabled:(BOOL)cheatsEnabled
{
Cheat.enabled = cheatsEnabled;
}
@end
@implementation S9xJoypad

View File

@ -16,5 +16,5 @@ FOUNDATION_EXPORT const unsigned char snes9x_frameworkVersionString[];
#import <snes9x_framework/port.h>
#import <snes9x_framework/mac-os.h>
#import <snes9x_framework/mac-cheat.h>

View File

@ -74,6 +74,11 @@
30A6F62423B2771A00630584 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30A6F62323B2771A00630584 /* MetalKit.framework */; };
30A6F62623B29EF500630584 /* shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 30A6F62523B29EF500630584 /* shaders.metal */; };
30A6F62823B29F8200630584 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30A6F62723B29F8200630584 /* Metal.framework */; };
30CF849527AEF5AF002B37A9 /* S9xCheatsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30CF849327AEF5AF002B37A9 /* S9xCheatsViewController.m */; };
30CF849627AEF5B0002B37A9 /* S9xCheatsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30CF849427AEF5AF002B37A9 /* S9xCheatsViewController.xib */; };
30CF849727AEFD4F002B37A9 /* mac-cheat.h in Headers */ = {isa = PBXBuildFile; fileRef = EAECB67304AC7FCE00A80003 /* mac-cheat.h */; settings = {ATTRIBUTES = (Public, ); }; };
30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */; };
30CF849D27AF0C61002B37A9 /* S9xCheatEditViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */; };
30D15CF322CE6B5A005BC352 /* snes9x_framework.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D15CF122CE6B5A005BC352 /* snes9x_framework.h */; settings = {ATTRIBUTES = (Public, ); }; };
30D15CFC22CE6B74005BC352 /* sha256.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85FEF90A20DDB18D00C038E9 /* sha256.cpp */; };
30D15CFE22CE6B74005BC352 /* bml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85FEF90620DDB15B00C038E9 /* bml.cpp */; };
@ -328,6 +333,12 @@
30AD1D2122FBB2EA000EE989 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/Snes9x.xib; sourceTree = "<group>"; };
30C49EF6250C0F2B007D04F8 /* Snes9xDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Snes9xDebug.entitlements; sourceTree = "<group>"; };
30CCAD422290472E00549AED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = /Users/buckley/Projects/snes9x/macosx/Info.plist; sourceTree = "<absolute>"; };
30CF849227AEF5AF002B37A9 /* S9xCheatsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xCheatsViewController.h; sourceTree = "<group>"; };
30CF849327AEF5AF002B37A9 /* S9xCheatsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xCheatsViewController.m; sourceTree = "<group>"; };
30CF849427AEF5AF002B37A9 /* S9xCheatsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xCheatsViewController.xib; sourceTree = "<group>"; };
30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xCheatEditViewController.h; sourceTree = "<group>"; };
30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xCheatEditViewController.m; sourceTree = "<group>"; };
30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xCheatEditViewController.xib; sourceTree = "<group>"; };
30D15CEF22CE6B5A005BC352 /* snes9x_framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = snes9x_framework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
30D15CF122CE6B5A005BC352 /* snes9x_framework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = snes9x_framework.h; sourceTree = "<group>"; };
30D15CF222CE6B5A005BC352 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -669,6 +680,7 @@
30714716230E379500917F82 /* Snes9x */ = {
isa = PBXGroup;
children = (
30CF849827AF0C3E002B37A9 /* Cheats */,
600546BE250F8F1700EC0977 /* S9xPreferences */,
30C49EF6250C0F2B007D04F8 /* Snes9xDebug.entitlements */,
30714717230E379500917F82 /* AppDelegate.h */,
@ -696,6 +708,19 @@
path = ReClassicfication;
sourceTree = "<group>";
};
30CF849827AF0C3E002B37A9 /* Cheats */ = {
isa = PBXGroup;
children = (
30CF849227AEF5AF002B37A9 /* S9xCheatsViewController.h */,
30CF849327AEF5AF002B37A9 /* S9xCheatsViewController.m */,
30CF849427AEF5AF002B37A9 /* S9xCheatsViewController.xib */,
30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */,
30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */,
30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */,
);
path = Cheats;
sourceTree = "<group>";
};
30D15CF022CE6B5A005BC352 /* snes9x framework */ = {
isa = PBXGroup;
children = (
@ -1118,6 +1143,7 @@
30D15DD522CE6BC9005BC352 /* 7z.h in Headers */,
30D15DD622CE6BC9005BC352 /* aribitcd.h in Headers */,
30D15DD722CE6BC9005BC352 /* ariconst.h in Headers */,
30CF849727AEFD4F002B37A9 /* mac-cheat.h in Headers */,
30D15DD822CE6BC9005BC352 /* ariprice.h in Headers */,
30D15DD922CE6BC9005BC352 /* btreecd.h in Headers */,
30D15DDA22CE6BC9005BC352 /* crc32.h in Headers */,
@ -1239,9 +1265,11 @@
30D709B5236F731B00AAB7C3 /* folder_SRAMs.icns in Resources */,
30D709B2236F731B00AAB7C3 /* CART.icns in Resources */,
30D709B7236F731B00AAB7C3 /* musicbox_ledon.icns in Resources */,
30CF849D27AF0C61002B37A9 /* S9xCheatEditViewController.xib in Resources */,
30D709B6236F731B00AAB7C3 /* folder_Freezes.icns in Resources */,
30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */,
306937E32636352100007ABB /* S9xEmulationPreferencesViewController.xib in Resources */,
30CF849627AEF5B0002B37A9 /* S9xCheatsViewController.xib in Resources */,
3071471E230E379600917F82 /* MainMenu.xib in Resources */,
306937DD26362B2400007ABB /* S9xSoundPreferencesViewController.xib in Resources */,
);
@ -1270,12 +1298,14 @@
309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */,
30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */,
306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */,
30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */,
306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */,
30714721230E379600917F82 /* main.m in Sources */,
306937CA2635EE5800007ABB /* S9xDisplayPreferencesViewController.m in Sources */,
30714719230E379500917F82 /* AppDelegate.m in Sources */,
306937DC26362B2400007ABB /* S9xSoundPreferencesViewController.m in Sources */,
3082C42A2379199F0081CA7C /* S9xApplication.m in Sources */,
30CF849527AEF5AF002B37A9 /* S9xCheatsViewController.m in Sources */,
30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */,
304B366C262E82B800F8DC8E /* S9xPreferencesConstants.m in Sources */,
);